[BOLT][DWARF] Implement monolithic DWARF5

Added implementation to support DWARF5 in monolithic mode.
Next step DWARF5 split dwarf support.

Reviewed By: maksfb

Differential Revision: https://reviews.llvm.org/D121876
This commit is contained in:
Alexander Yermolovich 2022-04-21 15:47:49 -07:00
parent 3348991106
commit 014cd37f51
20 changed files with 4066 additions and 158 deletions

View File

@ -204,6 +204,9 @@ class BinaryContext {
using DWOIdToCUMapType = std::unordered_map<uint64_t, DWARFUnit *>;
DWOIdToCUMapType DWOCUs;
bool ContainsDwarf5{false};
bool ContainsDwarfLegacy{false};
/// Preprocess DWO debug information.
void preprocessDWODebugInfo();
@ -234,7 +237,13 @@ public:
/// Get Number of DWOCUs in a map.
uint32_t getNumDWOCUs() { return DWOCUs.size(); }
const std::map<unsigned, DwarfLineTable> &getDwarfLineTables() const {
/// Returns true if DWARF5 is used.
bool isDWARF5Used() const { return ContainsDwarf5; }
/// Returns true if DWARF4 or lower is used.
bool isDWARFLegacyUsed() const { return ContainsDwarfLegacy; }
std::map<unsigned, DwarfLineTable> &getDwarfLineTables() {
return DwarfLineTablesCUMap;
}
@ -245,7 +254,8 @@ public:
Expected<unsigned> getDwarfFile(StringRef Directory, StringRef FileName,
unsigned FileNumber,
Optional<MD5::MD5Result> Checksum,
Optional<StringRef> Source, unsigned CUID);
Optional<StringRef> Source, unsigned CUID,
unsigned DWARFVersion);
/// [start memory address] -> [segment info] mapping.
std::map<uint64_t, SegmentInfo> SegmentMapInfo;

View File

@ -34,6 +34,21 @@ namespace llvm {
namespace bolt {
// DWARF5 Header in order of encoding.
// Types represent encodnig sizes.
using UnitLengthType = uint32_t;
using VersionType = uint16_t;
using AddressSizeType = uint8_t;
using SegmentSelectorType = uint8_t;
using OffsetEntryCountType = uint32_t;
/// Get DWARF5 Header size.
/// Rangelists and Loclists have the same header.
constexpr uint32_t getDWARF5RngListLocListHeaderSize() {
return sizeof(UnitLengthType) + sizeof(VersionType) +
sizeof(AddressSizeType) + sizeof(SegmentSelectorType) +
sizeof(OffsetEntryCountType);
}
class BinaryContext;
/// Address range representation. Takes less space than DWARFAddressRange.
@ -114,18 +129,23 @@ struct CUInfo {
};
using CUOffsetMap = std::map<uint32_t, CUInfo>;
enum class RangesWriterKind { DebugRangesWriter, DebugRangeListsWriter };
/// Serializes the .debug_ranges DWARF section.
class DebugRangesSectionWriter {
public:
DebugRangesSectionWriter();
DebugRangesSectionWriter(RangesWriterKind K) : Kind(K){};
virtual ~DebugRangesSectionWriter(){};
/// Add ranges with caching.
uint64_t
virtual uint64_t
addRanges(DebugAddressRangesVector &&Ranges,
std::map<DebugAddressRangesVector, uint64_t> &CachedRanges);
/// Add ranges and return offset into section.
uint64_t addRanges(const DebugAddressRangesVector &Ranges);
virtual uint64_t addRanges(const DebugAddressRangesVector &Ranges);
/// Returns an offset of an empty address ranges list that is always written
/// to .debug_ranges
@ -134,11 +154,18 @@ public:
/// Returns the SectionOffset.
uint64_t getSectionOffset();
std::unique_ptr<DebugBufferVector> finalize() {
/// Returns a buffer containing Ranges.
virtual std::unique_ptr<DebugBufferVector> finalize() {
return std::move(RangesBuffer);
}
private:
RangesWriterKind getKind() const { return Kind; }
static bool classof(const DebugRangesSectionWriter *Writer) {
return Writer->getKind() == RangesWriterKind::DebugRangesWriter;
}
protected:
std::unique_ptr<DebugBufferVector> RangesBuffer;
std::unique_ptr<raw_svector_ostream> RangesStream;
@ -151,6 +178,58 @@ private:
/// Offset of an empty address ranges list.
static constexpr uint64_t EmptyRangesOffset{0};
private:
RangesWriterKind Kind;
};
class DebugAddrWriter;
class DebugRangeListsSectionWriter : public DebugRangesSectionWriter {
public:
DebugRangeListsSectionWriter()
: DebugRangesSectionWriter(RangesWriterKind::DebugRangeListsWriter) {
RangesBuffer = std::make_unique<DebugBufferVector>();
RangesStream = std::make_unique<raw_svector_ostream>(*RangesBuffer);
};
virtual ~DebugRangeListsSectionWriter(){};
static void setAddressWriter(DebugAddrWriter *AddrW) { AddrWriter = AddrW; }
/// Add ranges with caching.
virtual uint64_t addRanges(
DebugAddressRangesVector &&Ranges,
std::map<DebugAddressRangesVector, uint64_t> &CachedRanges) override;
/// Add ranges and return offset into section.
virtual uint64_t addRanges(const DebugAddressRangesVector &Ranges) override;
virtual std::unique_ptr<DebugBufferVector> finalize() override {
return std::move(RangesBuffer);
}
/// Needs to be invoked before each CU is processed.
/// \p CUID is a unique ID of each CU.
void initSection(uint64_t CUID);
/// Writes out range lists for a current CU being processed.
void finalizeSection();
static bool classof(const DebugRangesSectionWriter *Writer) {
return Writer->getKind() == RangesWriterKind::DebugRangeListsWriter;
}
private:
static DebugAddrWriter *AddrWriter;
/// Unique ID of CU being processed.
uint64_t CUID{0};
/// Current relative offset of range list entry within this CUs rangelist
/// body.
uint32_t CurrentOffset{0};
/// Contains relative offset of each range list entry.
SmallVector<uint32_t, 1> RangeEntries;
std::unique_ptr<DebugBufferVector> CUBodyBuffer;
std::unique_ptr<raw_svector_ostream> CUBodyStream;
};
/// Serializes the .debug_aranges DWARF section.
@ -193,23 +272,25 @@ class DebugAddrWriter {
public:
DebugAddrWriter() = delete;
DebugAddrWriter(BinaryContext *BC_);
virtual ~DebugAddrWriter(){};
/// Given an address returns an index in .debug_addr.
/// Adds Address to map.
uint32_t getIndexFromAddress(uint64_t Address, uint64_t DWOId);
uint32_t getIndexFromAddress(uint64_t Address, uint64_t CUID);
/// Adds {Address, Index} to DWO ID CU.
void addIndexAddress(uint64_t Address, uint32_t Index, uint64_t DWOId);
void addIndexAddress(uint64_t Address, uint32_t Index, uint64_t CUID);
/// Creates consolidated .debug_addr section, and builds DWOID to offset map.
AddressSectionBuffer finalize();
virtual AddressSectionBuffer finalize();
/// Given DWOID returns offset of this CU in to .debug_addr section.
uint64_t getOffset(uint64_t DWOId);
/// Given DWARFUnit \p Unit returns offset of this CU in to .debug_addr
/// section.
virtual uint64_t getOffset(DWARFUnit &Unit);
/// Returns False if .debug_addr section was created..
bool isInitialized() const { return !AddressMaps.empty(); }
private:
protected:
class AddressForDWOCU {
public:
AddressToIndexMap::iterator find(uint64_t Adddress) {
@ -266,6 +347,18 @@ private:
std::mutex WriterMutex;
};
class DebugAddrWriterDwarf5 : public DebugAddrWriter {
public:
DebugAddrWriterDwarf5() = delete;
DebugAddrWriterDwarf5(BinaryContext *BC) : DebugAddrWriter(BC) {}
/// Creates consolidated .debug_addr section, and builds DWOID to offset map.
virtual AddressSectionBuffer finalize() override;
/// Given DWARFUnit \p Unit returns offset of this CU in to .debug_addr
/// section.
virtual uint64_t getOffset(DWARFUnit &Unit) override;
};
using DebugStrBufferVector = SmallVector<char, 16>;
class DebugStrWriter {
public:
@ -305,7 +398,8 @@ public:
virtual ~DebugLocWriter(){};
/// Writes out location lists and stores internal patches.
virtual void addList(uint64_t AttrOffset, DebugLocationsVector &&LocList);
virtual void addList(uint64_t AttrOffset, uint32_t LocListIndex,
DebugLocationsVector &&LocList);
/// Writes out locations in to a local buffer, and adds Debug Info patches.
virtual void finalize(uint64_t SectionOffset,
@ -314,6 +408,9 @@ public:
/// Return internal buffer.
virtual std::unique_ptr<DebugBufferVector> getBuffer();
/// Returns DWARF version.
uint8_t getDwarfVersion() const { return DwarfVersion; }
/// Offset of an empty location list.
static constexpr uint32_t EmptyListOffset = 0;
@ -325,13 +422,13 @@ public:
protected:
std::unique_ptr<DebugBufferVector> LocBuffer;
std::unique_ptr<raw_svector_ostream> LocStream;
/// Current offset in the section (updated as new entries are written).
/// Starts with 0 here since this only writes part of a full location lists
/// section. In the final section, the first 16 bytes are reserved for an
/// empty list.
uint32_t SectionOffset{0};
uint8_t DwarfVersion{4};
LocWriterKind Kind{LocWriterKind::DebugLocWriter};
private:
@ -354,9 +451,12 @@ class DebugLoclistWriter : public DebugLocWriter {
public:
~DebugLoclistWriter() {}
DebugLoclistWriter() = delete;
DebugLoclistWriter(BinaryContext *BC, uint64_t DWOId_)
: DebugLocWriter(BC), DWOId(DWOId_) {
DebugLoclistWriter(BinaryContext *BC, uint64_t CID,
uint32_t LocListsBaseAttrOffset, uint8_t DV, bool SD)
: DebugLocWriter(BC), CUID(CID),
LocListsBaseAttrOffset(LocListsBaseAttrOffset), IsSplitDwarf(SD) {
Kind = LocWriterKind::DebugLoclistWriter;
DwarfVersion = DV;
assert(DebugLoclistWriter::AddrWriter &&
"Please use SetAddressWriter to initialize "
"DebugAddrWriter before instantiation.");
@ -365,7 +465,7 @@ public:
static void setAddressWriter(DebugAddrWriter *AddrW) { AddrWriter = AddrW; }
/// Stores location lists internally to be written out during finalize phase.
virtual void addList(uint64_t AttrOffset,
virtual void addList(uint64_t AttrOffset, uint32_t LocListIndex,
DebugLocationsVector &&LocList) override;
/// Writes out locations in to a local buffer and applies debug info patches.
@ -373,15 +473,31 @@ public:
SimpleBinaryPatcher &DebugInfoPatcher) override;
/// Returns DWO ID.
uint64_t getDWOID() const { return DWOId; }
uint64_t getCUID() const { return CUID; }
LocWriterKind getKind() const { return DebugLocWriter::getKind(); }
static bool classof(const DebugLocWriter *Writer) {
return Writer->getKind() == LocWriterKind::DebugLoclistWriter;
}
bool isSplitDwarf() const { return IsSplitDwarf; }
constexpr static uint32_t InvalidIndex = UINT32_MAX;
constexpr static uint32_t InvalidLocListsBaseAttrOffset = UINT32_MAX;
private:
/// Writes out locations in to a local buffer and applies debug info patches.
void finalizeDWARFLegacy(uint64_t SectionOffset,
SimpleBinaryPatcher &DebugInfoPatcher);
/// Writes out locations in to a local buffer and applies debug info patches.
void finalizeDWARF5(uint64_t SectionOffset,
SimpleBinaryPatcher &DebugInfoPatcher);
struct LocPatch {
uint64_t AttrOffset{0};
uint32_t Index;
DebugLocationsVector LocList;
};
using LocPatchVec = SmallVector<LocPatch, 4>;
@ -395,7 +511,9 @@ private:
uint64_t Address{0};
};
static DebugAddrWriter *AddrWriter;
uint64_t DWOId{0};
uint64_t CUID{0};
uint32_t LocListsBaseAttrOffset{InvalidLocListsBaseAttrOffset};
bool IsSplitDwarf{false};
};
enum class PatcherKind { SimpleBinaryPatcher, DebugInfoBinaryPatcher };
@ -914,6 +1032,9 @@ private:
/// Raw data representing complete debug line section for the unit.
StringRef RawData;
/// DWARF Version
uint16_t DwarfVersion;
public:
/// Emit line info for all units in the binary context.
static void emit(BinaryContext &BC, MCStreamer &Streamer);
@ -937,6 +1058,14 @@ public:
void setLabel(MCSymbol *Label) { Header.Label = Label; }
/// Sets the root file \p Directory, \p FileName, optional \p CheckSum, and
/// optional \p Source.
void setRootFile(StringRef Directory, StringRef FileName,
Optional<MD5::MD5Result> Checksum,
Optional<StringRef> Source) {
Header.setRootFile(Directory, FileName, Checksum, Source);
}
/// Access to MC line info.
MCLineSection &getMCLineSections() { return MCLineSections; }
@ -956,6 +1085,12 @@ public:
void addRawContents(StringRef DebugLineContents) {
RawData = DebugLineContents;
}
/// Sets DWARF version for this line table.
void setDwarfVersion(uint16_t V) { DwarfVersion = V; }
// Returns DWARF Version for this line table.
uint16_t getDwarfVersion() const { return DwarfVersion; }
};
struct AttrInfo {

View File

@ -51,8 +51,7 @@ class DWARFRewriter {
/// .debug_abbrev section writer for the main binary.
std::unique_ptr<DebugAbbrevWriter> AbbrevWriter;
using LocWriters =
std::unordered_map<uint64_t, std::unique_ptr<DebugLocWriter>>;
using LocWriters = std::map<uint64_t, std::unique_ptr<DebugLocWriter>>;
/// Use a separate location list writer for each compilation unit
LocWriters LocListWritersByCU;
@ -68,11 +67,15 @@ class DWARFRewriter {
std::mutex LocListDebugInfoPatchesMutex;
/// DWARFLegacy is all DWARF versions before DWARF 5.
enum class DWARFVersion { DWARFLegacy, DWARF5 };
/// Update debug info for all DIEs in \p Unit.
void updateUnitDebugInfo(DWARFUnit &Unit,
DebugInfoBinaryPatcher &DebugInfoPatcher,
DebugAbbrevWriter &AbbrevWriter,
DebugLocWriter &DebugLocWriter,
DebugRangesSectionWriter &RangesWriter,
Optional<uint64_t> RangesBase = None);
/// Patches the binary for an object's address ranges to be updated.
@ -91,7 +94,8 @@ class DWARFRewriter {
Optional<uint64_t> RangesBase = None);
std::unique_ptr<DebugBufferVector>
makeFinalLocListsSection(SimpleBinaryPatcher &DebugInfoPatcher);
makeFinalLocListsSection(SimpleBinaryPatcher &DebugInfoPatcher,
DWARFVersion Version);
/// Finalize debug sections in the main binary.
CUOffsetMap finalizeDebugSections(DebugInfoBinaryPatcher &DebugInfoPatcher);

View File

@ -1325,14 +1325,13 @@ void BinaryContext::printGlobalSymbols(raw_ostream &OS) const {
}
}
Expected<unsigned>
BinaryContext::getDwarfFile(StringRef Directory, StringRef FileName,
unsigned FileNumber,
Optional<MD5::MD5Result> Checksum,
Optional<StringRef> Source, unsigned CUID) {
Expected<unsigned> BinaryContext::getDwarfFile(
StringRef Directory, StringRef FileName, unsigned FileNumber,
Optional<MD5::MD5Result> Checksum, Optional<StringRef> Source,
unsigned CUID, unsigned DWARFVersion) {
DwarfLineTable &Table = DwarfLineTablesCUMap[CUID];
return Table.tryGetFile(Directory, FileName, Checksum, Source,
Ctx->getDwarfVersion(), FileNumber);
return Table.tryGetFile(Directory, FileName, Checksum, Source, DWARFVersion,
FileNumber);
}
unsigned BinaryContext::addDebugFilenameToUnit(const uint32_t DestCUID,
@ -1360,7 +1359,9 @@ unsigned BinaryContext::addDebugFilenameToUnit(const uint32_t DestCUID,
dwarf::toString(FileNames[FileIndex - 1].Name))
FileName = *FName;
assert(FileName != "");
return cantFail(getDwarfFile(Dir, FileName, 0, None, None, DestCUID));
DWARFCompileUnit *DstUnit = DwCtx->getCompileUnitForOffset(DestCUID);
return cantFail(getDwarfFile(Dir, FileName, 0, None, None, DestCUID,
DstUnit->getVersion()));
}
std::vector<BinaryFunction *> BinaryContext::getSortedFunctions() {
@ -1458,8 +1459,15 @@ void BinaryContext::preprocessDebugInfo() {
if (containsAddress(Range.LowPC))
AllRanges.emplace_back(CURange{Range.LowPC, Range.HighPC, CU.get()});
}
ContainsDwarf5 |= CU->getVersion() >= 5;
ContainsDwarfLegacy |= CU->getVersion() < 5;
}
if (ContainsDwarf5 && ContainsDwarfLegacy)
llvm::errs() << "BOLT-WARNING: BOLT does not support mix mode binary with "
"DWARF5 and DWARF{2,3,4}.\n";
std::sort(AllRanges.begin(), AllRanges.end());
for (auto &KV : BinaryFunctions) {
const uint64_t FunctionAddress = KV.first;
@ -1496,7 +1504,8 @@ void BinaryContext::preprocessDebugInfo() {
StringRef GlobalPrefix = AsmInfo->getPrivateGlobalPrefix();
for (const std::unique_ptr<DWARFUnit> &CU : DwCtx->compile_units()) {
const uint64_t CUID = CU->getOffset();
getDwarfLineTable(CUID).setLabel(Ctx->getOrCreateSymbol(
DwarfLineTable &BinaryLineTable = getDwarfLineTable(CUID);
BinaryLineTable.setLabel(Ctx->getOrCreateSymbol(
GlobalPrefix + "line_table_start" + Twine(CUID)));
if (!ProcessedCUs.count(CU.get()))
@ -1507,26 +1516,45 @@ void BinaryContext::preprocessDebugInfo() {
const std::vector<DWARFDebugLine::FileNameEntry> &FileNames =
LineTable->Prologue.FileNames;
uint16_t DwarfVersion = LineTable->Prologue.getVersion();
if (DwarfVersion >= 5) {
Optional<MD5::MD5Result> Checksum = None;
if (LineTable->Prologue.ContentTypes.HasMD5)
Checksum = LineTable->Prologue.FileNames[0].Checksum;
BinaryLineTable.setRootFile(
CU->getCompilationDir(),
dwarf::toString(CU->getUnitDIE().find(dwarf::DW_AT_name), nullptr),
Checksum, None);
}
BinaryLineTable.setDwarfVersion(DwarfVersion);
// Assign a unique label to every line table, one per CU.
// Make sure empty debug line tables are registered too.
if (FileNames.empty()) {
cantFail(getDwarfFile("", "<unknown>", 0, None, None, CUID));
cantFail(
getDwarfFile("", "<unknown>", 0, None, None, CUID, DwarfVersion));
continue;
}
const uint32_t Offset = DwarfVersion < 5 ? 1 : 0;
for (size_t I = 0, Size = FileNames.size(); I != Size; ++I) {
// Dir indexes start at 1, as DWARF file numbers, and a dir index 0
// means empty dir.
StringRef Dir = "";
if (FileNames[I].DirIdx != 0)
if (FileNames[I].DirIdx != 0 || DwarfVersion >= 5)
if (Optional<const char *> DirName = dwarf::toString(
LineTable->Prologue
.IncludeDirectories[FileNames[I].DirIdx - 1]))
.IncludeDirectories[FileNames[I].DirIdx - Offset]))
Dir = *DirName;
StringRef FileName = "";
if (Optional<const char *> FName = dwarf::toString(FileNames[I].Name))
FileName = *FName;
assert(FileName != "");
cantFail(getDwarfFile(Dir, FileName, 0, None, None, CUID));
Optional<MD5::MD5Result> Checksum = None;
if (DwarfVersion >= 5 && LineTable->Prologue.ContentTypes.HasMD5)
Checksum = LineTable->Prologue.FileNames[I].Checksum;
cantFail(
getDwarfFile(Dir, FileName, 0, Checksum, None, CUID, DwarfVersion));
}
}

View File

@ -12,9 +12,11 @@
#include "bolt/Core/DebugData.h"
#include "bolt/Core/BinaryContext.h"
#include "bolt/Rewrite/RewriteInstance.h"
#include "bolt/Utils/Utils.h"
#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugAddr.h"
#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCObjectStreamer.h"
@ -118,6 +120,7 @@ DebugRangesSectionWriter::DebugRangesSectionWriter() {
// Add an empty range as the first entry;
SectionOffset +=
writeAddressRanges(*RangesStream.get(), DebugAddressRangesVector{});
Kind = RangesWriterKind::DebugRangesWriter;
}
uint64_t DebugRangesSectionWriter::addRanges(
@ -155,6 +158,94 @@ uint64_t DebugRangesSectionWriter::getSectionOffset() {
return SectionOffset;
}
DebugAddrWriter *DebugRangeListsSectionWriter::AddrWriter = nullptr;
uint64_t DebugRangeListsSectionWriter::addRanges(
DebugAddressRangesVector &&Ranges,
std::map<DebugAddressRangesVector, uint64_t> &CachedRanges) {
return addRanges(Ranges);
}
struct LocListsRangelistsHeader {
UnitLengthType UnitLength; // Size of loclist entris section, not including
// size of header.
VersionType Version;
AddressSizeType AddressSize;
SegmentSelectorType SegmentSelector;
OffsetEntryCountType OffsetEntryCount;
};
static std::unique_ptr<DebugBufferVector>
getDWARF5Header(const LocListsRangelistsHeader &Header) {
std::unique_ptr<DebugBufferVector> HeaderBuffer =
std::make_unique<DebugBufferVector>();
std::unique_ptr<raw_svector_ostream> HeaderStream =
std::make_unique<raw_svector_ostream>(*HeaderBuffer);
// 7.29 length of the set of entries for this compilation unit, not including
// the length field itself
const uint32_t HeaderSize =
getDWARF5RngListLocListHeaderSize() - sizeof(UnitLengthType);
support::endian::write(*HeaderStream, Header.UnitLength + HeaderSize,
support::little);
support::endian::write(*HeaderStream, Header.Version, support::little);
support::endian::write(*HeaderStream, Header.AddressSize, support::little);
support::endian::write(*HeaderStream, Header.SegmentSelector,
support::little);
support::endian::write(*HeaderStream, Header.OffsetEntryCount,
support::little);
return HeaderBuffer;
}
uint64_t DebugRangeListsSectionWriter::addRanges(
const DebugAddressRangesVector &Ranges) {
std::lock_guard<std::mutex> Lock(WriterMutex);
RangeEntries.push_back(CurrentOffset);
for (const DebugAddressRange &Range : Ranges) {
support::endian::write(*CUBodyStream,
static_cast<uint8_t>(dwarf::DW_RLE_startx_length),
support::little);
const uint32_t Index = AddrWriter->getIndexFromAddress(Range.LowPC, CUID);
encodeULEB128(Index, *CUBodyStream);
encodeULEB128(Range.HighPC - Range.LowPC, *CUBodyStream);
}
support::endian::write(*CUBodyStream,
static_cast<uint8_t>(dwarf::DW_RLE_end_of_list),
support::little);
CurrentOffset = CUBodyBuffer->size();
return RangeEntries.size() - 1;
}
void DebugRangeListsSectionWriter::finalizeSection() {
std::unique_ptr<DebugBufferVector> CUArrayBuffer =
std::make_unique<DebugBufferVector>();
std::unique_ptr<raw_svector_ostream> CUArrayStream =
std::make_unique<raw_svector_ostream>(*CUArrayBuffer);
constexpr uint32_t SizeOfArrayEntry = 4;
const uint32_t SizeOfArraySection = RangeEntries.size() * SizeOfArrayEntry;
for (uint32_t Offset : RangeEntries)
support::endian::write(*CUArrayStream, Offset + SizeOfArraySection,
support::little);
std::unique_ptr<DebugBufferVector> Header = getDWARF5Header(
{static_cast<uint32_t>(SizeOfArraySection + CUBodyBuffer.get()->size()),
5, 8, 0, static_cast<uint32_t>(RangeEntries.size())});
*RangesStream << *Header;
*RangesStream << *CUArrayBuffer;
*RangesStream << *CUBodyBuffer;
SectionOffset = RangesBuffer->size();
}
void DebugRangeListsSectionWriter::initSection(uint64_t CUId_) {
CUBodyBuffer = std::make_unique<DebugBufferVector>();
CUBodyStream = std::make_unique<raw_svector_ostream>(*CUBodyBuffer);
RangeEntries.clear();
CurrentOffset = 0;
CUID = CUId_;
}
void DebugARangesSectionWriter::addCURanges(uint64_t CUOffset,
DebugAddressRangesVector &&Ranges) {
std::lock_guard<std::mutex> Lock(CUAddressRangesMutex);
@ -220,13 +311,12 @@ void DebugAddrWriter::AddressForDWOCU::dump() {
for (auto &Pair : SortedMap)
dbgs() << Twine::utohexstr(Pair.second) << "\t" << Pair.first << "\n";
}
uint32_t DebugAddrWriter::getIndexFromAddress(uint64_t Address,
uint64_t DWOId) {
uint32_t DebugAddrWriter::getIndexFromAddress(uint64_t Address, uint64_t CUID) {
std::lock_guard<std::mutex> Lock(WriterMutex);
if (!AddressMaps.count(DWOId))
AddressMaps[DWOId] = AddressForDWOCU();
if (!AddressMaps.count(CUID))
AddressMaps[CUID] = AddressForDWOCU();
AddressForDWOCU &Map = AddressMaps[DWOId];
AddressForDWOCU &Map = AddressMaps[CUID];
auto Entry = Map.find(Address);
if (Entry == Map.end()) {
auto Index = Map.getNextIndex();
@ -240,9 +330,9 @@ uint32_t DebugAddrWriter::getIndexFromAddress(uint64_t Address,
// IndexToAddrss. Case3) Address is in the map but Index is lower. Need to
// update AddressToIndex and IndexToAddress
void DebugAddrWriter::addIndexAddress(uint64_t Address, uint32_t Index,
uint64_t DWOId) {
uint64_t CUID) {
std::lock_guard<std::mutex> Lock(WriterMutex);
AddressForDWOCU &Map = AddressMaps[DWOId];
AddressForDWOCU &Map = AddressMaps[CUID];
auto Entry = Map.find(Address);
if (Entry != Map.end()) {
if (Entry->second > Index)
@ -265,6 +355,7 @@ AddressSectionBuffer DebugAddrWriter::finalize() {
if (!DWOId)
continue;
auto AM = AddressMaps.find(*DWOId);
assert(AM != AddressMaps.end() && "Address Map not found.");
// Adding to map even if it did not contribute to .debug_addr.
// The Skeleton CU will still have DW_AT_GNU_addr_base.
DWOIdToOffsetMap[*DWOId] = Buffer.size();
@ -306,9 +397,97 @@ AddressSectionBuffer DebugAddrWriter::finalize() {
return Buffer;
}
AddressSectionBuffer DebugAddrWriterDwarf5::finalize() {
// Need to layout all sections within .debug_addr
// Within each section sort Address by index.
AddressSectionBuffer Buffer;
raw_svector_ostream AddressStream(Buffer);
const endianness Endian =
BC->DwCtx->isLittleEndian() ? support::little : support::big;
const DWARFSection &AddrSec = BC->DwCtx->getDWARFObj().getAddrSection();
DWARFDataExtractor AddrData(BC->DwCtx->getDWARFObj(), AddrSec, Endian, 0);
DWARFDebugAddrTable AddrTable;
DIDumpOptions DumpOpts;
constexpr uint32_t HeaderSize = 8;
for (std::unique_ptr<DWARFUnit> &CU : BC->DwCtx->compile_units()) {
const uint64_t CUID = CU->getOffset();
const uint8_t AddrSize = CU->getAddressByteSize();
auto Iter = AddressMaps.find(CUID);
// A case where CU has entry in .debug_addr, but we don't modify addresses
// for it.
if (Iter == AddressMaps.end()) {
Iter = AddressMaps.insert({CUID, AddressForDWOCU()}).first;
Optional<uint64_t> BaseOffset = CU->getAddrOffsetSectionBase();
if (!BaseOffset)
continue;
// Address base offset is to the first entry.
// The size of header is 8 bytes.
uint64_t Offset = *BaseOffset - HeaderSize;
if (Error Err = AddrTable.extract(AddrData, &Offset, 5, AddrSize,
DumpOpts.WarningHandler)) {
DumpOpts.RecoverableErrorHandler(std::move(Err));
continue;
}
uint32_t Index = 0;
for (uint64_t Addr : AddrTable.getAddressEntries())
Iter->second.insert(Addr, Index++);
}
uint64_t DebugAddrWriter::getOffset(uint64_t DWOId) {
auto Iter = DWOIdToOffsetMap.find(DWOId);
DWOIdToOffsetMap[CUID] = Buffer.size() + HeaderSize;
std::vector<IndexAddressPair> SortedMap(Iter->second.indexToAddressBegin(),
Iter->second.indexToAdddessEnd());
// Sorting address in increasing order of indices.
std::sort(SortedMap.begin(), SortedMap.end(),
[](const IndexAddressPair &A, const IndexAddressPair &B) {
return A.first < B.first;
});
// Writing out Header
const uint32_t Length = SortedMap.size() * AddrSize + 4;
support::endian::write(AddressStream, Length, Endian);
support::endian::write(AddressStream, static_cast<uint16_t>(5), Endian);
support::endian::write(AddressStream, static_cast<uint8_t>(AddrSize),
Endian);
support::endian::write(AddressStream, static_cast<uint8_t>(0), Endian);
uint32_t Counter = 0;
auto writeAddress = [&](uint64_t Address) -> void {
++Counter;
switch (AddrSize) {
default:
llvm_unreachable("Address Size is invalid.");
break;
case 4:
support::endian::write(AddressStream, static_cast<uint32_t>(Address),
Endian);
break;
case 8:
support::endian::write(AddressStream, Address, Endian);
break;
}
};
for (const IndexAddressPair &Val : SortedMap) {
while (Val.first > Counter)
writeAddress(0);
writeAddress(Val.second);
}
}
return Buffer;
}
uint64_t DebugAddrWriter::getOffset(DWARFUnit &Unit) {
Optional<uint64_t> DWOId = Unit.getDWOId();
assert(DWOId && "Can't get offset, not a skeleton CU.");
auto Iter = DWOIdToOffsetMap.find(*DWOId);
assert(Iter != DWOIdToOffsetMap.end() &&
"Offset in to.debug_addr was not found for DWO ID.");
return Iter->second;
}
uint64_t DebugAddrWriterDwarf5::getOffset(DWARFUnit &Unit) {
auto Iter = DWOIdToOffsetMap.find(Unit.getOffset());
assert(Iter != DWOIdToOffsetMap.end() &&
"Offset in to.debug_addr was not found for DWO ID.");
return Iter->second;
@ -319,7 +498,7 @@ DebugLocWriter::DebugLocWriter(BinaryContext *BC) {
LocStream = std::make_unique<raw_svector_ostream>(*LocBuffer);
}
void DebugLocWriter::addList(uint64_t AttrOffset,
void DebugLocWriter::addList(uint64_t AttrOffset, uint32_t LocListIndex,
DebugLocationsVector &&LocList) {
if (LocList.empty()) {
EmptyAttrLists.push_back(AttrOffset);
@ -345,9 +524,9 @@ void DebugLocWriter::addList(uint64_t AttrOffset,
LocListDebugInfoPatches.push_back({AttrOffset, EntryOffset});
}
void DebugLoclistWriter::addList(uint64_t AttrOffset,
void DebugLoclistWriter::addList(uint64_t AttrOffset, uint32_t LocListIndex,
DebugLocationsVector &&LocList) {
Patches.push_back({AttrOffset, std::move(LocList)});
Patches.push_back({AttrOffset, LocListIndex, std::move(LocList)});
}
std::unique_ptr<DebugBufferVector> DebugLocWriter::getBuffer() {
@ -368,8 +547,95 @@ void DebugLocWriter::finalize(uint64_t SectionOffset,
DebugLocWriter::EmptyListOffset);
}
void DebugLoclistWriter::finalize(uint64_t SectionOffset,
SimpleBinaryPatcher &DebugInfoPatcher) {
static void writeEmptyListDwarf5(raw_svector_ostream &Stream) {
support::endian::write(Stream, static_cast<uint32_t>(4), support::little);
support::endian::write(Stream, static_cast<uint8_t>(dwarf::DW_LLE_start_end),
support::little);
const char Zeroes[16] = {0};
Stream << StringRef(Zeroes, 16);
encodeULEB128(0, Stream);
support::endian::write(
Stream, static_cast<uint8_t>(dwarf::DW_LLE_end_of_list), support::little);
}
void DebugLoclistWriter::finalizeDWARF5(uint64_t SectionOffset,
SimpleBinaryPatcher &DebugInfoPatcher) {
std::unique_ptr<DebugBufferVector> LocArrayBuffer =
std::make_unique<DebugBufferVector>();
std::unique_ptr<raw_svector_ostream> LocArrayStream =
std::make_unique<raw_svector_ostream>(*LocArrayBuffer);
std::unique_ptr<DebugBufferVector> LocBodyBuffer =
std::make_unique<DebugBufferVector>();
std::unique_ptr<raw_svector_ostream> LocBodyStream =
std::make_unique<raw_svector_ostream>(*LocBodyBuffer);
const uint32_t SizeOfArraySection = Patches.size() * sizeof(uint32_t);
std::sort(Patches.begin(), Patches.end(),
[](const LocPatch &P1, const LocPatch &P2) -> bool {
return P1.Index < P2.Index;
});
if (LocListsBaseAttrOffset != InvalidLocListsBaseAttrOffset)
DebugInfoPatcher.addLE32Patch(LocListsBaseAttrOffset,
SectionOffset +
getDWARF5RngListLocListHeaderSize());
uint32_t Index{0};
for (LocPatch &Patch : Patches) {
const uint32_t EntryOffset = LocBodyBuffer->size();
if (Patch.LocList.empty()) {
if (Patch.Index == DebugLoclistWriter::InvalidIndex)
DebugInfoPatcher.addLE32Patch(Patch.AttrOffset, EntryOffset);
writeEmptyListDwarf5(*LocBodyStream);
continue;
}
assert(Patch.Index == DebugLoclistWriter::InvalidIndex ||
Patch.Index == Index++ && "Gap in LocList Index Array.");
std::vector<uint64_t> OffsetsArray;
for (const DebugLocationEntry &Entry : Patch.LocList) {
support::endian::write(*LocBodyStream,
static_cast<uint8_t>(dwarf::DW_LLE_startx_length),
support::little);
const uint32_t Index = AddrWriter->getIndexFromAddress(Entry.LowPC, CUID);
encodeULEB128(Index, *LocBodyStream);
encodeULEB128(Entry.HighPC - Entry.LowPC, *LocBodyStream);
encodeULEB128(Entry.Expr.size(), *LocBodyStream);
*LocBodyStream << StringRef(
reinterpret_cast<const char *>(Entry.Expr.data()), Entry.Expr.size());
}
support::endian::write(*LocBodyStream,
static_cast<uint8_t>(dwarf::DW_LLE_end_of_list),
support::little);
// Write out IndexArray
support::endian::write(
*LocArrayStream,
static_cast<uint32_t>(SizeOfArraySection + EntryOffset),
support::little);
// Don't need to patch Index since we are re-using them.
if (Patch.Index == DebugLoclistWriter::InvalidIndex)
DebugInfoPatcher.addLE32Patch(Patch.AttrOffset, EntryOffset);
clearList(Patch.LocList);
}
if (!Patches.empty()) {
std::unique_ptr<DebugBufferVector> Header =
getDWARF5Header({static_cast<uint32_t>(SizeOfArraySection +
LocBodyBuffer.get()->size()),
5, 8, 0, static_cast<uint32_t>(Patches.size())});
*LocStream << *Header;
*LocStream << *LocArrayBuffer;
*LocStream << *LocBodyBuffer;
}
clearList(Patches);
}
void DebugLoclistWriter::finalizeDWARFLegacy(
uint64_t SectionOffset, SimpleBinaryPatcher &DebugInfoPatcher) {
for (LocPatch &Patch : Patches) {
if (Patch.LocList.empty()) {
DebugInfoPatcher.addLE32Patch(Patch.AttrOffset,
@ -381,7 +647,7 @@ void DebugLoclistWriter::finalize(uint64_t SectionOffset,
support::endian::write(*LocStream,
static_cast<uint8_t>(dwarf::DW_LLE_startx_length),
support::little);
uint32_t Index = AddrWriter->getIndexFromAddress(Entry.LowPC, DWOId);
const uint32_t Index = AddrWriter->getIndexFromAddress(Entry.LowPC, CUID);
encodeULEB128(Index, *LocStream);
// TODO: Support DWARF5
@ -403,6 +669,14 @@ void DebugLoclistWriter::finalize(uint64_t SectionOffset,
clearList(Patches);
}
void DebugLoclistWriter::finalize(uint64_t SectionOffset,
SimpleBinaryPatcher &DebugInfoPatcher) {
if (DwarfVersion < 5)
finalizeDWARFLegacy(SectionOffset, DebugInfoPatcher);
else
finalizeDWARF5(SectionOffset, DebugInfoPatcher);
}
DebugAddrWriter *DebugLoclistWriter::AddrWriter = nullptr;
void DebugInfoBinaryPatcher::addUnitBaseOffsetLabel(uint64_t Offset) {
@ -1154,7 +1428,7 @@ static inline void emitDwarfLineTable(
MCOS->emitULEB128IntValue(Column);
}
if (Discriminator != LineEntry.getDiscriminator() &&
MCOS->getContext().getDwarfVersion() >= 4) {
MCOS->getContext().getDwarfVersion() >= 2) {
Discriminator = LineEntry.getDiscriminator();
unsigned Size = getULEB128Size(Discriminator);
MCOS->emitInt8(dwarf::DW_LNS_extended_op);
@ -1228,6 +1502,31 @@ void DwarfLineTable::emitCU(MCStreamer *MCOS, MCDwarfLineTableParams Params,
MCOS->emitLabel(LineEndSym);
}
// Helper function to parse .debug_line_str, and populate one we are using.
// For functions that we do not modify we output them as raw data.
// Re-constructing .debug_line_str so that offsets are correct for those
// debut line tables.
// Bonus is that when we output a final binary we can re-use .debug_line_str
// section. So we don't have to do the SHF_ALLOC trick we did with
// .debug_line.
static void parseAndPopulateDebugLineStr(BinarySection &LineStrSection,
MCDwarfLineStr &LineStr,
BinaryContext &BC,
MCStreamer &Streamer) {
DataExtractor StrData(LineStrSection.getContents(),
BC.DwCtx->isLittleEndian(), 0);
uint64_t Offset = 0;
while (StrData.isValidOffset(Offset)) {
Error Err = Error::success();
const char *CStr = StrData.getCStr(&Offset, &Err);
if (Err) {
errs() << "BOLT-ERROR: could not extract string from .debug_line_str";
continue;
}
LineStr.emitRef(&Streamer, CStr);
}
}
void DwarfLineTable::emit(BinaryContext &BC, MCStreamer &Streamer) {
MCAssembler &Assembler =
static_cast<MCObjectStreamer *>(&Streamer)->getAssembler();
@ -1240,19 +1539,39 @@ void DwarfLineTable::emit(BinaryContext &BC, MCStreamer &Streamer) {
// in doing so create an unnecessary (if empty) section.
if (LineTables.empty())
return;
// In a v5 non-split line table, put the strings in a separate section.
Optional<MCDwarfLineStr> LineStr(None);
if (BC.Ctx->getDwarfVersion() >= 5)
ErrorOr<BinarySection &> LineStrSection =
BC.getUniqueSectionByName(".debug_line_str");
// Some versions of GCC output DWARF5 .debug_info, but DWARF4 or lower
// .debug_line
if (LineStrSection) {
LineStr = MCDwarfLineStr(*BC.Ctx);
parseAndPopulateDebugLineStr(*LineStrSection, *LineStr, BC, Streamer);
}
// Switch to the section where the table will be emitted into.
Streamer.SwitchSection(BC.MOFI->getDwarfLineSection());
const uint16_t DwarfVersion = BC.Ctx->getDwarfVersion();
// Handle the rest of the Compile Units.
for (auto &CUIDTablePair : LineTables) {
Streamer.getContext().setDwarfVersion(
CUIDTablePair.second.getDwarfVersion());
CUIDTablePair.second.emitCU(&Streamer, Params, LineStr, BC);
}
// Resetting DWARF version for rest of the flow.
BC.Ctx->setDwarfVersion(DwarfVersion);
// Still need to write the section out for the ExecutionEngine, and temp in
// memory object we are constructing.
if (LineStr) {
LineStr->emitSection(&Streamer);
SmallString<0> Data = LineStr->getFinalizedData();
BC.registerOrUpdateNoteSection(".debug_line_str", copyByteArray(Data.str()),
Data.size());
}
}
} // namespace bolt

View File

@ -32,6 +32,7 @@
#include "llvm/Support/Endian.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/LEB128.h"
#include "llvm/Support/ThreadPool.h"
#include "llvm/Support/ToolOutputFile.h"
#include <algorithm>
@ -72,6 +73,19 @@ static Optional<AttrInfo> findAttributeInfo(const DWARFDie DIE,
return None;
return findAttributeInfo(DIE, AbbrevDecl, *Index);
}
/// Finds attributes FormValue and Offset.
///
/// \param DIE die to look up in.
/// \param Attrs finds the first attribute that matches and extracts it.
/// \return an optional AttrInfo with DWARFFormValue and Offset.
Optional<AttrInfo> findAttributeInfo(const DWARFDie DIE,
std::vector<dwarf::Attribute> Attrs) {
for (dwarf::Attribute &Attr : Attrs)
if (Optional<AttrInfo> Info = findAttributeInfo(DIE, Attr))
return Info;
return None;
}
} // namespace bolt
} // namespace llvm
@ -158,24 +172,40 @@ void DWARFRewriter::updateDebugInfo() {
static_cast<DebugInfoBinaryPatcher *>(DebugInfo->getPatcher());
ARangesSectionWriter = std::make_unique<DebugARangesSectionWriter>();
RangesSectionWriter = std::make_unique<DebugRangesSectionWriter>();
StrWriter = std::make_unique<DebugStrWriter>(&BC);
AbbrevWriter = std::make_unique<DebugAbbrevWriter>(*BC.DwCtx);
AddrWriter = std::make_unique<DebugAddrWriter>(&BC);
DebugLoclistWriter::setAddressWriter(AddrWriter.get());
uint64_t NumCUs = BC.DwCtx->getNumCompileUnits();
if ((opts::NoThreads || opts::DeterministicDebugInfo) &&
BC.getNumDWOCUs() == 0) {
// Use single entry for efficiency when running single-threaded
NumCUs = 1;
if (BC.isDWARF5Used()) {
// Disabling none deterministic mode for dwarf5, to keep implementation
// simpler.
opts::DeterministicDebugInfo = true;
AddrWriter = std::make_unique<DebugAddrWriterDwarf5>(&BC);
RangesSectionWriter = std::make_unique<DebugRangeListsSectionWriter>();
DebugRangeListsSectionWriter::setAddressWriter(AddrWriter.get());
} else {
AddrWriter = std::make_unique<DebugAddrWriter>(&BC);
RangesSectionWriter = std::make_unique<DebugRangesSectionWriter>();
}
LocListWritersByCU.reserve(NumCUs);
DebugLoclistWriter::setAddressWriter(AddrWriter.get());
for (size_t CUIndex = 0; CUIndex < NumCUs; ++CUIndex)
LocListWritersByCU[CUIndex] = std::make_unique<DebugLocWriter>(&BC);
size_t CUIndex = 0;
for (std::unique_ptr<DWARFUnit> &CU : BC.DwCtx->compile_units()) {
if (CU->getVersion() >= 5) {
uint32_t AttrInfoOffset =
DebugLoclistWriter::InvalidLocListsBaseAttrOffset;
if (Optional<AttrInfo> AttrInfoVal =
findAttributeInfo(CU->getUnitDIE(), dwarf::DW_AT_loclists_base))
AttrInfoOffset = AttrInfoVal->Offset;
LocListWritersByCU[CUIndex] = std::make_unique<DebugLoclistWriter>(
&BC, CU->isDWOUnit() ? *CU->getDWOId() : CU->getOffset(),
AttrInfoOffset, 5, false);
} else {
LocListWritersByCU[CUIndex] = std::make_unique<DebugLocWriter>(&BC);
}
++CUIndex;
}
// Unordered maps to handle name collision if output DWO directory is
// specified.
@ -185,8 +215,8 @@ void DWARFRewriter::updateDebugInfo() {
auto updateDWONameCompDir = [&](DWARFUnit &Unit) -> void {
const DWARFDie &DIE = Unit.getUnitDIE();
Optional<AttrInfo> AttrInfoVal =
findAttributeInfo(DIE, dwarf::DW_AT_GNU_dwo_name);
Optional<AttrInfo> AttrInfoVal = findAttributeInfo(
DIE, {dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name});
(void)AttrInfoVal;
assert(AttrInfoVal && "Skeleton CU doesn't have dwo_name.");
@ -234,8 +264,8 @@ void DWARFRewriter::updateDebugInfo() {
std::lock_guard<std::mutex> Lock(AccessMutex);
DebugLocWriter =
LocListWritersByCU
.insert(
{*DWOId, std::make_unique<DebugLoclistWriter>(&BC, *DWOId)})
.insert({*DWOId, std::make_unique<DebugLoclistWriter>(
&BC, *DWOId, 0, Unit->getVersion(), true)})
.first->second.get();
}
DebugInfoBinaryPatcher *DwoDebugInfoPatcher =
@ -251,7 +281,7 @@ void DWARFRewriter::updateDebugInfo() {
DebugAbbrevWriter *DWOAbbrevWriter =
createBinaryDWOAbbrevWriter((*SplitCU)->getContext(), *DWOId);
updateUnitDebugInfo(*(*SplitCU), *DwoDebugInfoPatcher, *DWOAbbrevWriter,
*DebugLocWriter);
*DebugLocWriter, *RangesSectionWriter);
DwoDebugInfoPatcher->clearDestinationLabels();
if (!DwoDebugInfoPatcher->getWasRangBasedUsed())
RangesBase = None;
@ -261,18 +291,33 @@ void DWARFRewriter::updateDebugInfo() {
std::lock_guard<std::mutex> Lock(AccessMutex);
DebugLocWriter = LocListWritersByCU[CUIndex].get();
}
if (Unit->getVersion() >= 5) {
RangesBase = RangesSectionWriter->getSectionOffset() +
getDWARF5RngListLocListHeaderSize();
reinterpret_cast<DebugRangeListsSectionWriter *>(
RangesSectionWriter.get())
->initSection(Unit->getOffset());
}
DebugInfoPatcher->addUnitBaseOffsetLabel(Unit->getOffset());
updateUnitDebugInfo(*Unit, *DebugInfoPatcher, *AbbrevWriter,
*DebugLocWriter, RangesBase);
*DebugLocWriter, *RangesSectionWriter, RangesBase);
if (Unit->getVersion() >= 5)
reinterpret_cast<DebugRangeListsSectionWriter *>(
RangesSectionWriter.get())
->finalizeSection();
};
CUIndex = 0;
if (opts::NoThreads || opts::DeterministicDebugInfo) {
for (std::unique_ptr<DWARFUnit> &CU : BC.DwCtx->compile_units())
processUnitDIE(0, CU.get());
for (std::unique_ptr<DWARFUnit> &CU : BC.DwCtx->compile_units()) {
processUnitDIE(CUIndex, CU.get());
if (CU->getVersion() >= 5)
++CUIndex;
}
} else {
// Update unit debug info in parallel
ThreadPool &ThreadPool = ParallelUtilities::getThreadPool();
size_t CUIndex = 0;
for (std::unique_ptr<DWARFUnit> &CU : BC.DwCtx->compile_units()) {
ThreadPool.async(processUnitDIE, CUIndex, CU.get());
CUIndex++;
@ -291,9 +336,18 @@ void DWARFRewriter::updateDebugInfo() {
updateGdbIndexSection(OffsetMap);
}
static uint64_t getCUId(DWARFUnit &Unit) {
if (Unit.getVersion() >= 5)
return Unit.getOffset();
assert(Unit.isDWOUnit() && "Unit is not Skeleton CU.");
return *Unit.getDWOId();
}
void DWARFRewriter::updateUnitDebugInfo(
DWARFUnit &Unit, DebugInfoBinaryPatcher &DebugInfoPatcher,
DebugAbbrevWriter &AbbrevWriter, DebugLocWriter &DebugLocWriter,
DebugRangesSectionWriter &RangesSectionWriter,
Optional<uint64_t> RangesBase) {
// Cache debug ranges so that the offset for identical ranges could be reused.
std::map<DebugAddressRangesVector, uint64_t> CachedRanges;
@ -332,7 +386,7 @@ void DWARFRewriter::updateUnitDebugInfo(
DebugAddressRangesVector OutputRanges =
BC.translateModuleAddressRanges(ModuleRanges);
const uint64_t RangesSectionOffset =
RangesSectionWriter->addRanges(OutputRanges);
RangesSectionWriter.addRanges(OutputRanges);
if (!Unit.isDWOUnit())
ARangesSectionWriter->addCURanges(Unit.getOffset(),
std::move(OutputRanges));
@ -371,7 +425,7 @@ void DWARFRewriter::updateUnitDebugInfo(
FunctionRanges.push_back({0, 0});
updateDWARFObjectAddressRanges(
DIE, RangesSectionWriter->addRanges(FunctionRanges), DebugInfoPatcher,
DIE, RangesSectionWriter.addRanges(FunctionRanges), DebugInfoPatcher,
AbbrevWriter);
break;
@ -380,8 +434,7 @@ void DWARFRewriter::updateUnitDebugInfo(
case dwarf::DW_TAG_inlined_subroutine:
case dwarf::DW_TAG_try_block:
case dwarf::DW_TAG_catch_block: {
uint64_t RangesSectionOffset =
RangesSectionWriter->getEmptyRangesOffset();
uint64_t RangesSectionOffset = RangesSectionWriter.getEmptyRangesOffset();
Expected<DWARFAddressRangesVector> RangesOrError = DIE.getAddressRanges();
const BinaryFunction *Function =
RangesOrError && !RangesOrError->empty()
@ -396,7 +449,7 @@ void DWARFRewriter::updateUnitDebugInfo(
<< Twine::utohexstr(DIE.getOffset()) << " in CU at 0x"
<< Twine::utohexstr(Unit.getOffset()) << '\n';
});
RangesSectionOffset = RangesSectionWriter->addRanges(
RangesSectionOffset = RangesSectionWriter.addRanges(
std::move(OutputRanges), CachedRanges);
} else if (!RangesOrError) {
consumeError(RangesOrError.takeError());
@ -426,6 +479,12 @@ void DWARFRewriter::updateUnitDebugInfo(
if (SectionAddress)
BaseAddress = SectionAddress->Address;
if (Unit.getVersion() >= 5) {
Optional<uint64_t> LocOffset = Unit.getLoclistOffset(Offset);
assert(LocOffset && "Location Offset is invalid.");
Offset = *LocOffset;
}
Error E = Unit.getLocationTable().visitLocationList(
&Offset, [&](const DWARFLocationEntry &Entry) {
switch (Entry.Kind) {
@ -433,11 +492,12 @@ void DWARFRewriter::updateUnitDebugInfo(
llvm_unreachable("Unsupported DWARFLocationEntry Kind.");
case dwarf::DW_LLE_end_of_list:
return false;
case dwarf::DW_LLE_base_address:
case dwarf::DW_LLE_base_address: {
assert(Entry.SectionIndex == SectionedAddress::UndefSection &&
"absolute address expected");
BaseAddress = Entry.Value0;
break;
}
case dwarf::DW_LLE_offset_pair:
assert(
(Entry.SectionIndex == SectionedAddress::UndefSection &&
@ -447,9 +507,18 @@ void DWARFRewriter::updateUnitDebugInfo(
BaseAddress + Entry.Value0, BaseAddress + Entry.Value1,
Entry.Loc});
break;
case dwarf::DW_LLE_startx_length:
assert(Unit.isDWOUnit() &&
"None DWO Unit with DW_LLE_startx_length encoding.");
case dwarf::DW_RLE_start_length:
InputLL.emplace_back(DebugLocationEntry{
Entry.Value0, Entry.Value0 + Entry.Value1, Entry.Loc});
break;
case dwarf::DW_LLE_base_addressx: {
Optional<object::SectionedAddress> EntryAddress =
Unit.getAddrOffsetSectionItem(Entry.Value0);
assert(EntryAddress && "base Address not found.");
BaseAddress = EntryAddress->Address;
break;
}
case dwarf::DW_LLE_startx_length: {
Optional<object::SectionedAddress> EntryAddress =
Unit.getAddrOffsetSectionItem(Entry.Value0);
assert(EntryAddress && "Address does not exist.");
@ -458,6 +527,18 @@ void DWARFRewriter::updateUnitDebugInfo(
EntryAddress->Address + Entry.Value1, Entry.Loc});
break;
}
case dwarf::DW_LLE_startx_endx: {
Optional<object::SectionedAddress> StartAddress =
Unit.getAddrOffsetSectionItem(Entry.Value0);
assert(StartAddress && "Start Address does not exist.");
Optional<object::SectionedAddress> EndAddress =
Unit.getAddrOffsetSectionItem(Entry.Value1);
assert(EndAddress && "Start Address does not exist.");
InputLL.emplace_back(DebugLocationEntry{
StartAddress->Address, EndAddress->Address, Entry.Loc});
break;
}
}
return true;
});
@ -469,42 +550,90 @@ void DWARFRewriter::updateUnitDebugInfo(
<< Twine::utohexstr(Unit.getOffset()) << '\n';
} else {
const uint64_t Address = InputLL.front().LowPC;
DebugLocationsVector OutputLL;
if (const BinaryFunction *Function =
BC.getBinaryFunctionContainingAddress(Address)) {
DebugLocationsVector OutputLL =
Function->translateInputToOutputLocationList(InputLL);
OutputLL = Function->translateInputToOutputLocationList(InputLL);
LLVM_DEBUG(if (OutputLL.empty()) {
dbgs() << "BOLT-DEBUG: location list translated to an empty "
"one at 0x"
<< Twine::utohexstr(DIE.getOffset()) << " in CU at 0x"
<< Twine::utohexstr(Unit.getOffset()) << '\n';
});
DebugLocWriter.addList(AttrOffset, std::move(OutputLL));
} else {
// It's possible for a subprogram to be removed and to have
// address of 0. Adding this entry to output to preserve debug
// information.
OutputLL = InputLL;
}
uint32_t LocListIndex = 0;
dwarf::Form Form = Value.getForm();
if (Form == dwarf::DW_FORM_sec_offset ||
Form == dwarf::DW_FORM_data4) {
// For DWARF5 we can access location list entry either using
// index, or offset. If it's offset, then it's from begnning of
// the file. This implementation was before we could add entries
// to the DIE. For DWARF4 this is no-op.
// TODO: For DWARF5 convert all the offset based entries to index
// based, and insert loclist_base if necessary.
LocListIndex = DebugLoclistWriter::InvalidIndex;
} else if (Form == dwarf::DW_FORM_loclistx) {
LocListIndex = Value.getRawUValue();
} else {
llvm_unreachable("Unsupported LocList access Form.");
}
DebugLocWriter.addList(AttrOffset, LocListIndex,
std::move(OutputLL));
}
} else {
assert((Value.isFormClass(DWARFFormValue::FC_Exprloc) ||
Value.isFormClass(DWARFFormValue::FC_Block)) &&
"unexpected DW_AT_location form");
if (Unit.isDWOUnit()) {
if (Unit.isDWOUnit() || Unit.getVersion() >= 5) {
ArrayRef<uint8_t> Expr = *Value.getAsBlock();
DataExtractor Data(
StringRef((const char *)Expr.data(), Expr.size()),
Unit.getContext().isLittleEndian(), 0);
DWARFExpression LocExpr(Data, Unit.getAddressByteSize(),
Unit.getFormParams().Format);
uint32_t PrevOffset = 0;
constexpr uint32_t SizeOfOpcode = 1;
constexpr uint32_t SizeOfForm = 1;
for (auto &Expr : LocExpr) {
if (Expr.getCode() != dwarf::DW_OP_GNU_addr_index)
if (!(Expr.getCode() == dwarf::DW_OP_GNU_addr_index ||
Expr.getCode() == dwarf::DW_OP_addrx))
continue;
uint64_t Index = Expr.getRawOperand(0);
const uint64_t Index = Expr.getRawOperand(0);
Optional<object::SectionedAddress> EntryAddress =
Unit.getAddrOffsetSectionItem(Index);
assert(EntryAddress && "Address is not found.");
assert(Index <= std::numeric_limits<uint32_t>::max() &&
"Invalid Operand Index.");
AddrWriter->addIndexAddress(EntryAddress->Address,
static_cast<uint32_t>(Index),
*Unit.getDWOId());
if (Expr.getCode() == dwarf::DW_OP_addrx) {
const uint32_t EncodingSize =
Expr.getOperandEndOffset(0) - PrevOffset - SizeOfOpcode;
const uint32_t Index = AddrWriter->getIndexFromAddress(
EntryAddress->Address, getCUId(Unit));
// Encoding new size.
SmallString<8> Tmp;
raw_svector_ostream OSE(Tmp);
encodeULEB128(Index, OSE);
DebugInfoPatcher.addUDataPatch(AttrOffset, Tmp.size() + 1, 1);
DebugInfoPatcher.addUDataPatch(AttrOffset + PrevOffset +
SizeOfOpcode + SizeOfForm,
Index, EncodingSize);
} else {
// TODO: Re-do this as DWARF5.
AddrWriter->addIndexAddress(EntryAddress->Address,
static_cast<uint32_t>(Index),
getCUId(Unit));
}
if (Expr.getDescription().Op[1] ==
DWARFExpression::Operation::SizeNA)
PrevOffset = Expr.getOperandEndOffset(0);
else
PrevOffset = Expr.getOperandEndOffset(1);
}
}
}
@ -531,15 +660,20 @@ void DWARFRewriter::updateUnitDebugInfo(
"DW_FORM_LLVM_addrx_offset is not supported");
std::lock_guard<std::mutex> Lock(DebugInfoPatcherMutex);
if (Form == dwarf::DW_FORM_GNU_addr_index) {
assert(Unit.isDWOUnit() &&
"DW_FORM_GNU_addr_index in Non DWO unit.");
uint64_t Index = Value.getRawUValue();
const uint64_t Index = Value.getRawUValue();
// If there is no new address, storing old address.
// Re-using Index to make implementation easier.
// DW_FORM_GNU_addr_index is variable lenght encoding so we either
// have to create indices of same sizes, or use same index.
// DW_FORM_GNU_addr_index is variable lenght encoding
// so we either have to create indices of same sizes, or use same
// index.
// TODO: We can now re-write .debug_info. This can be simplified to
// just getting a new index and creating a patch.
AddrWriter->addIndexAddress(NewAddress ? NewAddress : Address,
Index, *Unit.getDWOId());
Index, getCUId(Unit));
} else if (Form == dwarf::DW_FORM_addrx) {
const uint32_t Index = AddrWriter->getIndexFromAddress(
NewAddress ? NewAddress : Address, getCUId(Unit));
DebugInfoPatcher.addUDataPatch(AttrOffset, Index, AttrVal->Size);
} else {
DebugInfoPatcher.addLE64Patch(AttrOffset, NewAddress);
}
@ -613,6 +747,9 @@ void DWARFRewriter::updateDWARFObjectAddressRanges(
// are needed for ranges base.
Optional<AttrInfo> RangesBaseAttrInfo =
findAttributeInfo(DIE, dwarf::DW_AT_GNU_ranges_base);
if (!RangesBaseAttrInfo)
RangesBaseAttrInfo = findAttributeInfo(DIE, dwarf::DW_AT_rnglists_base);
if (RangesBaseAttrInfo) {
DebugInfoPatcher.addLE32Patch(RangesBaseAttrInfo->Offset,
static_cast<uint32_t>(*RangesBase),
@ -623,15 +760,28 @@ void DWARFRewriter::updateDWARFObjectAddressRanges(
Optional<AttrInfo> LowPCAttrInfo =
findAttributeInfo(DIE, dwarf::DW_AT_low_pc);
if (AbbreviationDecl->findAttributeIndex(dwarf::DW_AT_ranges)) {
if (Optional<AttrInfo> AttrVal =
findAttributeInfo(DIE, dwarf::DW_AT_ranges)) {
// Case 1: The object was already non-contiguous and had DW_AT_ranges.
// In this case we simply need to update the value of DW_AT_ranges
// and introduce DW_AT_GNU_ranges_base if required.
Optional<AttrInfo> AttrVal = findAttributeInfo(DIE, dwarf::DW_AT_ranges);
std::lock_guard<std::mutex> Lock(DebugInfoPatcherMutex);
DebugInfoPatcher.addLE32Patch(
AttrVal->Offset, DebugRangesOffset - DebugInfoPatcher.getRangeBase(),
AttrVal->Size);
// For DWARF5 converting all of DW_AT_ranges into DW_FORM_rnglistx
bool Converted = false;
if (DIE.getDwarfUnit()->getVersion() >= 5 &&
AttrVal->V.getForm() == dwarf::DW_FORM_sec_offset) {
AbbrevWriter.addAttributePatch(*DIE.getDwarfUnit(), AbbreviationDecl,
dwarf::DW_AT_ranges, dwarf::DW_AT_ranges,
dwarf::DW_FORM_rnglistx);
Converted = true;
}
if (Converted || AttrVal->V.getForm() == dwarf::DW_FORM_rnglistx)
DebugInfoPatcher.addUDataPatch(AttrVal->Offset, DebugRangesOffset,
AttrVal->Size);
else
DebugInfoPatcher.addLE32Patch(
AttrVal->Offset, DebugRangesOffset - DebugInfoPatcher.getRangeBase(),
AttrVal->Size);
if (!RangesBase) {
if (LowPCAttrInfo &&
@ -766,15 +916,27 @@ DWARFRewriter::finalizeDebugSections(DebugInfoBinaryPatcher &DebugInfoPatcher) {
std::unique_ptr<DebugBufferVector> RangesSectionContents =
RangesSectionWriter->finalize();
BC.registerOrUpdateNoteSection(".debug_ranges",
copyByteArray(*RangesSectionContents),
RangesSectionContents->size());
BC.registerOrUpdateNoteSection(
llvm::isa<DebugRangeListsSectionWriter>(*RangesSectionWriter)
? ".debug_rnglists"
: ".debug_ranges",
copyByteArray(*RangesSectionContents), RangesSectionContents->size());
std::unique_ptr<DebugBufferVector> LocationListSectionContents =
makeFinalLocListsSection(DebugInfoPatcher);
BC.registerOrUpdateNoteSection(".debug_loc",
copyByteArray(*LocationListSectionContents),
LocationListSectionContents->size());
if (BC.isDWARF5Used()) {
std::unique_ptr<DebugBufferVector> LocationListSectionContents =
makeFinalLocListsSection(DebugInfoPatcher, DWARFVersion::DWARF5);
BC.registerOrUpdateNoteSection(".debug_loclists",
copyByteArray(*LocationListSectionContents),
LocationListSectionContents->size());
}
if (BC.isDWARFLegacyUsed()) {
std::unique_ptr<DebugBufferVector> LocationListSectionContents =
makeFinalLocListsSection(DebugInfoPatcher, DWARFVersion::DWARFLegacy);
BC.registerOrUpdateNoteSection(".debug_loc",
copyByteArray(*LocationListSectionContents),
LocationListSectionContents->size());
}
// AddrWriter should be finalized after debug_loc since more addresses can be
// added there.
@ -785,12 +947,39 @@ DWARFRewriter::finalizeDebugSections(DebugInfoBinaryPatcher &DebugInfoPatcher) {
AddressSectionContents.size());
for (auto &CU : BC.DwCtx->compile_units()) {
DWARFDie DIE = CU->getUnitDIE();
if (Optional<AttrInfo> AttrVal =
findAttributeInfo(DIE, dwarf::DW_AT_GNU_addr_base)) {
uint64_t Offset = AddrWriter->getOffset(*CU->getDWOId());
DebugInfoPatcher.addLE32Patch(
AttrVal->Offset, static_cast<int32_t>(Offset), AttrVal->Size);
uint64_t Offset = 0;
uint64_t AttrOffset = 0;
uint32_t Size = 0;
Optional<AttrInfo> AttrValGnu =
findAttributeInfo(DIE, dwarf::DW_AT_GNU_addr_base);
Optional<AttrInfo> AttrVal =
findAttributeInfo(DIE, dwarf::DW_AT_addr_base);
Offset = AddrWriter->getOffset(*CU);
if (AttrValGnu) {
AttrOffset = AttrValGnu->Offset;
Size = AttrValGnu->Size;
}
if (AttrVal) {
AttrOffset = AttrVal->Offset;
Size = AttrVal->Size;
}
if (AttrValGnu || AttrVal) {
DebugInfoPatcher.addLE32Patch(AttrOffset, static_cast<int32_t>(Offset),
Size);
} else if (CU->getVersion() >= 5) {
// A case where we were not using .debug_addr section, but after update
// now using it.
const DWARFAbbreviationDeclaration *Abbrev =
DIE.getAbbreviationDeclarationPtr();
AbbrevWriter->addAttribute(*CU, Abbrev, dwarf::DW_AT_addr_base,
dwarf::DW_FORM_sec_offset);
DebugInfoPatcher.insertNewEntry(DIE, static_cast<int32_t>(Offset));
} else
llvm_unreachable(
"DWO CU uses .debug_address, but DW_AT_GNU_addr_base is missing.");
}
}
@ -808,13 +997,22 @@ DWARFRewriter::finalizeDebugSections(DebugInfoBinaryPatcher &DebugInfoPatcher) {
if (Unit->getAbbreviationsOffset() == NewAbbrevOffset)
continue;
// DWARFv4
// DWARFv4 or earlier
// unit_length - 4 bytes
// version - 2 bytes
// So + 6 to patch debug_abbrev_offset
constexpr uint64_t AbbrevFieldOffset = 6;
if (!Unit->isTypeUnit()) {
DebugInfoPatcher.addLE32Patch(Unit->getOffset() + AbbrevFieldOffset,
constexpr uint64_t AbbrevFieldOffsetLegacy = 6;
// DWARFv5
// unit_length - 4 bytes
// version - 2 bytes
// unit_type - 1 byte
// address_size - 1 byte
// So + 8 to patch debug_abbrev_offset
constexpr uint64_t AbbrevFieldOffsetV5 = 8;
uint64_t AbbrevOffset =
Unit->getVersion() >= 5 ? AbbrevFieldOffsetV5 : AbbrevFieldOffsetLegacy;
if (!Unit->isTypeUnit() || Unit->getVersion() >= 5) {
DebugInfoPatcher.addLE32Patch(Unit->getOffset() + AbbrevOffset,
static_cast<uint32_t>(NewAbbrevOffset));
continue;
}
@ -826,7 +1024,7 @@ DWARFRewriter::finalizeDebugSections(DebugInfoBinaryPatcher &DebugInfoPatcher) {
DebugTypesPatcher =
static_cast<SimpleBinaryPatcher *>(DebugTypes->getPatcher());
}
DebugTypesPatcher->addLE32Patch(Unit->getOffset() + AbbrevFieldOffset,
DebugTypesPatcher->addLE32Patch(Unit->getOffset() + AbbrevOffset,
static_cast<uint32_t>(NewAbbrevOffset));
}
@ -1033,7 +1231,7 @@ void DWARFRewriter::writeDWP(
if (!DWOCU)
continue;
assert(CU->getVersion() == 4 && "For DWP output only DWARF4 is supported");
assert(CU->getVersion() <= 4 && "For DWP output only DWARF4 is supported");
UnitIndexEntry CurEntry = {};
CurEntry.DWOName =
dwarf::toString(CU->getUnitDIE().find(
@ -1292,25 +1490,40 @@ void DWARFRewriter::updateGdbIndexSection(CUOffsetMap &CUMap) {
}
std::unique_ptr<DebugBufferVector>
DWARFRewriter::makeFinalLocListsSection(SimpleBinaryPatcher &DebugInfoPatcher) {
DWARFRewriter::makeFinalLocListsSection(SimpleBinaryPatcher &DebugInfoPatcher,
DWARFVersion Version) {
auto LocBuffer = std::make_unique<DebugBufferVector>();
auto LocStream = std::make_unique<raw_svector_ostream>(*LocBuffer);
auto Writer =
std::unique_ptr<MCObjectWriter>(BC.createObjectWriter(*LocStream));
uint64_t SectionOffset = 0;
// Add an empty list as the first entry;
const char Zeroes[16] = {0};
*LocStream << StringRef(Zeroes, 16);
SectionOffset += 2 * 8;
if (LocListWritersByCU.empty() ||
LocListWritersByCU.begin()->second.get()->getDwarfVersion() < 5) {
// Should be fine for both DWARF4 and DWARF5?
const char Zeroes[16] = {0};
*LocStream << StringRef(Zeroes, 16);
SectionOffset += 2 * 8;
}
for (std::pair<const uint64_t, std::unique_ptr<DebugLocWriter>> &Loc :
LocListWritersByCU) {
DebugLocWriter *LocWriter = Loc.second.get();
if (auto *LocListWriter = llvm::dyn_cast<DebugLoclistWriter>(LocWriter)) {
auto *LocListWriter = llvm::dyn_cast<DebugLoclistWriter>(LocWriter);
if (Version == DWARFVersion::DWARF5 &&
(!LocListWriter || LocListWriter->getDwarfVersion() <= 4))
continue;
if (Version == DWARFVersion::DWARFLegacy &&
(LocListWriter && LocListWriter->getDwarfVersion() >= 5))
continue;
if (LocListWriter && (LocListWriter->getDwarfVersion() <= 4 ||
(LocListWriter->getDwarfVersion() >= 5 &&
LocListWriter->isSplitDwarf()))) {
SimpleBinaryPatcher *Patcher =
getBinaryDWODebugInfoPatcher(LocListWriter->getDWOID());
getBinaryDWODebugInfoPatcher(LocListWriter->getCUID());
LocListWriter->finalize(0, *Patcher);
continue;
}
@ -1336,7 +1549,8 @@ void getRangeAttrData(DWARFDie DIE, Optional<AttrInfo> &LowPCVal,
dwarf::Form HighPCForm = HighPCVal->V.getForm();
if (LowPCForm != dwarf::DW_FORM_addr &&
LowPCForm != dwarf::DW_FORM_GNU_addr_index) {
LowPCForm != dwarf::DW_FORM_GNU_addr_index &&
LowPCForm != dwarf::DW_FORM_addrx) {
errs() << "BOLT-WARNING: unexpected low_pc form value. Cannot update DIE "
<< "at offset 0x" << Twine::utohexstr(DIE.getOffset()) << "\n";
return;
@ -1351,7 +1565,8 @@ void getRangeAttrData(DWARFDie DIE, Optional<AttrInfo> &LowPCVal,
return;
}
if ((LowPCOffset == -1U || (LowPCOffset + 8 != HighPCOffset)) &&
LowPCForm != dwarf::DW_FORM_GNU_addr_index) {
LowPCForm != dwarf::DW_FORM_GNU_addr_index &&
LowPCForm != dwarf::DW_FORM_addrx) {
errs() << "BOLT-WARNING: high_pc expected immediately after low_pc. "
<< "Cannot update DIE at offset 0x"
<< Twine::utohexstr(DIE.getOffset()) << '\n';
@ -1364,24 +1579,27 @@ void getRangeAttrData(DWARFDie DIE, Optional<AttrInfo> &LowPCVal,
void DWARFRewriter::convertToRangesPatchAbbrev(
const DWARFUnit &Unit, const DWARFAbbreviationDeclaration *Abbrev,
DebugAbbrevWriter &AbbrevWriter, Optional<uint64_t> RangesBase) {
auto getAttributeForm = [&Abbrev](const dwarf::Attribute Attr) {
Optional<uint32_t> Index = Abbrev->findAttributeIndex(Attr);
assert(Index && "attribute not found");
return Abbrev->getFormByIndex(*Index);
};
dwarf::Form LowPCForm = getAttributeForm(dwarf::DW_AT_low_pc);
// DW_FORM_GNU_addr_index is already variable encoding so nothing to do
// there.
if (RangesBase) {
assert(LowPCForm != dwarf::DW_FORM_GNU_addr_index);
AbbrevWriter.addAttribute(Unit, Abbrev, dwarf::DW_AT_GNU_ranges_base,
dwarf::DW_FORM_sec_offset);
dwarf::Attribute RangeBaseAttribute = dwarf::DW_AT_GNU_ranges_base;
dwarf::Form RangesForm = dwarf::DW_FORM_sec_offset;
if (Unit.getVersion() >= 5) {
RangeBaseAttribute = dwarf::DW_AT_rnglists_base;
RangesForm = dwarf::DW_FORM_rnglistx;
}
// If we hit this point it means we converted subprogram DIEs from
// low_pc/high_pc into ranges. The CU originally didn't have DW_AT_*_base, so
// we are adding it here.
if (RangesBase)
AbbrevWriter.addAttribute(Unit, Abbrev, RangeBaseAttribute,
dwarf::DW_FORM_sec_offset);
// Converting DW_AT_high_pc into DW_AT_ranges.
// For DWARF4 it's DW_FORM_sec_offset.
// For DWARF5 it can be either DW_FORM_sec_offset or DW_FORM_rnglistx.
// For consistency for DWARF5 we always use DW_FORM_rnglistx.
AbbrevWriter.addAttributePatch(Unit, Abbrev, dwarf::DW_AT_high_pc,
dwarf::DW_AT_ranges,
dwarf::DW_FORM_sec_offset);
dwarf::DW_AT_ranges, RangesForm);
}
void DWARFRewriter::convertToRangesPatchDebugInfo(
@ -1395,19 +1613,42 @@ void DWARFRewriter::convertToRangesPatchDebugInfo(
std::lock_guard<std::mutex> Lock(DebugInfoPatcherMutex);
uint32_t BaseOffset = 0;
if (LowPCVal->V.getForm() == dwarf::DW_FORM_GNU_addr_index) {
dwarf::Form LowForm = LowPCVal->V.getForm();
// In DWARF4 for DW_AT_low_pc in binary DW_FORM_addr is used. In the DWO
// section DW_FORM_GNU_addr_index is used. So for if we are converting
// DW_AT_low_pc/DW_AT_high_pc and see DW_FORM_GNU_addr_index. We are
// converting in DWO section, and DW_AT_ranges [DW_FORM_sec_offset] is
// relative to DW_AT_GNU_ranges_base.
if (LowForm == dwarf::DW_FORM_GNU_addr_index) {
// Use ULEB128 for the value.
DebugInfoPatcher.addUDataPatch(LowPCOffset, 0,
std::abs(int(HighPCOffset - LowPCOffset)));
DebugInfoPatcher.addUDataPatch(LowPCOffset, 0, LowPCVal->Size);
// Ranges are relative to DW_AT_GNU_ranges_base.
BaseOffset = DebugInfoPatcher.getRangeBase();
} else {
DebugInfoPatcher.addLE64Patch(LowPCOffset, 0);
// If DW_AT_GNU_ranges_base was inserted.
// In DWARF 5 we can have DW_AT_low_pc either as DW_FORM_addr, or
// DW_FORM_addrx. Former is when DW_AT_rnglists_base is present. Latter is
// when it's absent.
if (LowForm == dwarf::DW_FORM_addrx) {
uint32_t Index =
AddrWriter->getIndexFromAddress(0, DIE.getDwarfUnit()->getOffset());
DebugInfoPatcher.addUDataPatch(LowPCOffset, Index, LowPCVal->Size);
} else
DebugInfoPatcher.addLE64Patch(LowPCOffset, 0);
// Original CU didn't have DW_AT_*_base. We converted it's children (or
// dwo), so need to insert it into CU.
if (RangesBase)
reinterpret_cast<DebugInfoBinaryPatcher &>(DebugInfoPatcher)
.insertNewEntry(DIE, *RangesBase);
}
DebugInfoPatcher.addLE32Patch(HighPCOffset, RangesSectionOffset - BaseOffset,
HighPCVal->Size);
// HighPC was conveted into DW_AT_ranges.
// For DWARF5 we only access ranges throught index.
if (DIE.getDwarfUnit()->getVersion() >= 5)
DebugInfoPatcher.addUDataPatch(HighPCOffset, RangesSectionOffset,
HighPCVal->Size);
else
DebugInfoPatcher.addLE32Patch(
HighPCOffset, RangesSectionOffset - BaseOffset, HighPCVal->Size);
}

View File

@ -311,8 +311,9 @@ WriteBoltInfoSection("bolt-info",
constexpr const char *RewriteInstance::SectionsToOverwrite[];
std::vector<std::string> RewriteInstance::DebugSectionsToOverwrite = {
".debug_abbrev", ".debug_aranges", ".debug_line", ".debug_loc",
".debug_ranges", ".gdb_index", ".debug_addr"};
".debug_abbrev", ".debug_aranges", ".debug_line", ".debug_line_str",
".debug_loc", ".debug_loclists", ".debug_ranges", ".debug_rnglists",
".gdb_index", ".debug_addr"};
const char RewriteInstance::TimerGroupName[] = "rewrite";
const char RewriteInstance::TimerGroupDesc[] = "Rewrite passes";

View File

@ -0,0 +1,424 @@
# clang++ helper.cpp -g -O2 -S
# int fooVar = 0;
# void useFoo(int * x) {
# *x += 4;
# }
#
# int foo(int argc) {
# int x = argc;
# useFoo(&x);
# return x;
# }
.text
.file "foo.cpp"
.file 0 "/testLocListMultiple" "foo.cpp" md5 0x9410f31145d031fcc1f2464b809e409a
.globl _Z6useFooPi # -- Begin function _Z6useFooPi
.p2align 4, 0x90
.type _Z6useFooPi,@function
_Z6useFooPi: # @_Z6useFooPi
.Lfunc_begin0:
.loc 0 2 0 # foo.cpp:2:0
.cfi_startproc
# %bb.0: # %entry
#DEBUG_VALUE: useFoo:x <- $rdi
.loc 0 3 4 prologue_end # foo.cpp:3:4
addl $4, (%rdi)
.loc 0 4 1 # foo.cpp:4:1
retq
.Ltmp0:
.Lfunc_end0:
.size _Z6useFooPi, .Lfunc_end0-_Z6useFooPi
.cfi_endproc
# -- End function
.globl _Z3fooi # -- Begin function _Z3fooi
.p2align 4, 0x90
.type _Z3fooi,@function
_Z3fooi: # @_Z3fooi
.Lfunc_begin1:
.loc 0 6 0 # foo.cpp:6:0
.cfi_startproc
# %bb.0: # %entry
#DEBUG_VALUE: foo:argc <- $edi
#DEBUG_VALUE: foo:x <- $edi
# kill: def $edi killed $edi def $rdi
#DEBUG_VALUE: useFoo:x <- undef
.loc 0 3 4 prologue_end # foo.cpp:3:4
leal 4(%rdi), %eax
.Ltmp1:
#DEBUG_VALUE: foo:x <- $eax
.loc 0 9 4 # foo.cpp:9:4
retq
.Ltmp2:
.Lfunc_end1:
.size _Z3fooi, .Lfunc_end1-_Z3fooi
.cfi_endproc
# -- End function
.type fooVar,@object # @fooVar
.bss
.globl fooVar
.p2align 2
fooVar:
.long 0 # 0x0
.size fooVar, 4
.section .debug_loclists,"",@progbits
.long .Ldebug_list_header_end0-.Ldebug_list_header_start0 # Length
.Ldebug_list_header_start0:
.short 5 # Version
.byte 8 # Address size
.byte 0 # Segment selector size
.long 1 # Offset entry count
.Lloclists_table_base0:
.long .Ldebug_loc0-.Lloclists_table_base0
.Ldebug_loc0:
.byte 4 # DW_LLE_offset_pair
.uleb128 .Lfunc_begin1-.Lfunc_begin0 # starting offset
.uleb128 .Ltmp1-.Lfunc_begin0 # ending offset
.byte 1 # Loc expr size
.byte 85 # super-register DW_OP_reg5
.byte 4 # DW_LLE_offset_pair
.uleb128 .Ltmp1-.Lfunc_begin0 # starting offset
.uleb128 .Lfunc_end1-.Lfunc_begin0 # ending offset
.byte 1 # Loc expr size
.byte 80 # super-register DW_OP_reg0
.byte 0 # DW_LLE_end_of_list
.Ldebug_list_header_end0:
.section .debug_abbrev,"",@progbits
.byte 1 # Abbreviation Code
.byte 17 # DW_TAG_compile_unit
.byte 1 # DW_CHILDREN_yes
.byte 37 # DW_AT_producer
.byte 37 # DW_FORM_strx1
.byte 19 # DW_AT_language
.byte 5 # DW_FORM_data2
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 114 # DW_AT_str_offsets_base
.byte 23 # DW_FORM_sec_offset
.byte 16 # DW_AT_stmt_list
.byte 23 # DW_FORM_sec_offset
.byte 27 # DW_AT_comp_dir
.byte 37 # DW_FORM_strx1
.byte 17 # DW_AT_low_pc
.byte 27 # DW_FORM_addrx
.byte 18 # DW_AT_high_pc
.byte 6 # DW_FORM_data4
.byte 115 # DW_AT_addr_base
.byte 23 # DW_FORM_sec_offset
.ascii "\214\001" # DW_AT_loclists_base
.byte 23 # DW_FORM_sec_offset
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 2 # Abbreviation Code
.byte 52 # DW_TAG_variable
.byte 0 # DW_CHILDREN_no
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 73 # DW_AT_type
.byte 19 # DW_FORM_ref4
.byte 63 # DW_AT_external
.byte 25 # DW_FORM_flag_present
.byte 58 # DW_AT_decl_file
.byte 11 # DW_FORM_data1
.byte 59 # DW_AT_decl_line
.byte 11 # DW_FORM_data1
.byte 2 # DW_AT_location
.byte 24 # DW_FORM_exprloc
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 3 # Abbreviation Code
.byte 36 # DW_TAG_base_type
.byte 0 # DW_CHILDREN_no
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 62 # DW_AT_encoding
.byte 11 # DW_FORM_data1
.byte 11 # DW_AT_byte_size
.byte 11 # DW_FORM_data1
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 4 # Abbreviation Code
.byte 46 # DW_TAG_subprogram
.byte 1 # DW_CHILDREN_yes
.byte 17 # DW_AT_low_pc
.byte 27 # DW_FORM_addrx
.byte 18 # DW_AT_high_pc
.byte 6 # DW_FORM_data4
.byte 64 # DW_AT_frame_base
.byte 24 # DW_FORM_exprloc
.byte 122 # DW_AT_call_all_calls
.byte 25 # DW_FORM_flag_present
.byte 49 # DW_AT_abstract_origin
.byte 19 # DW_FORM_ref4
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 5 # Abbreviation Code
.byte 5 # DW_TAG_formal_parameter
.byte 0 # DW_CHILDREN_no
.byte 2 # DW_AT_location
.byte 24 # DW_FORM_exprloc
.byte 49 # DW_AT_abstract_origin
.byte 19 # DW_FORM_ref4
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 6 # Abbreviation Code
.byte 46 # DW_TAG_subprogram
.byte 1 # DW_CHILDREN_yes
.byte 110 # DW_AT_linkage_name
.byte 37 # DW_FORM_strx1
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 58 # DW_AT_decl_file
.byte 11 # DW_FORM_data1
.byte 59 # DW_AT_decl_line
.byte 11 # DW_FORM_data1
.byte 63 # DW_AT_external
.byte 25 # DW_FORM_flag_present
.byte 32 # DW_AT_inline
.byte 33 # DW_FORM_implicit_const
.byte 1
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 7 # Abbreviation Code
.byte 5 # DW_TAG_formal_parameter
.byte 0 # DW_CHILDREN_no
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 58 # DW_AT_decl_file
.byte 11 # DW_FORM_data1
.byte 59 # DW_AT_decl_line
.byte 11 # DW_FORM_data1
.byte 73 # DW_AT_type
.byte 19 # DW_FORM_ref4
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 8 # Abbreviation Code
.byte 15 # DW_TAG_pointer_type
.byte 0 # DW_CHILDREN_no
.byte 73 # DW_AT_type
.byte 19 # DW_FORM_ref4
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 9 # Abbreviation Code
.byte 46 # DW_TAG_subprogram
.byte 1 # DW_CHILDREN_yes
.byte 17 # DW_AT_low_pc
.byte 27 # DW_FORM_addrx
.byte 18 # DW_AT_high_pc
.byte 6 # DW_FORM_data4
.byte 64 # DW_AT_frame_base
.byte 24 # DW_FORM_exprloc
.byte 122 # DW_AT_call_all_calls
.byte 25 # DW_FORM_flag_present
.byte 110 # DW_AT_linkage_name
.byte 37 # DW_FORM_strx1
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 58 # DW_AT_decl_file
.byte 11 # DW_FORM_data1
.byte 59 # DW_AT_decl_line
.byte 11 # DW_FORM_data1
.byte 73 # DW_AT_type
.byte 19 # DW_FORM_ref4
.byte 63 # DW_AT_external
.byte 25 # DW_FORM_flag_present
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 10 # Abbreviation Code
.byte 5 # DW_TAG_formal_parameter
.byte 0 # DW_CHILDREN_no
.byte 2 # DW_AT_location
.byte 24 # DW_FORM_exprloc
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 58 # DW_AT_decl_file
.byte 11 # DW_FORM_data1
.byte 59 # DW_AT_decl_line
.byte 11 # DW_FORM_data1
.byte 73 # DW_AT_type
.byte 19 # DW_FORM_ref4
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 11 # Abbreviation Code
.byte 52 # DW_TAG_variable
.byte 0 # DW_CHILDREN_no
.byte 2 # DW_AT_location
.byte 34 # DW_FORM_loclistx
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 58 # DW_AT_decl_file
.byte 11 # DW_FORM_data1
.byte 59 # DW_AT_decl_line
.byte 11 # DW_FORM_data1
.byte 73 # DW_AT_type
.byte 19 # DW_FORM_ref4
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 12 # Abbreviation Code
.byte 29 # DW_TAG_inlined_subroutine
.byte 0 # DW_CHILDREN_no
.byte 49 # DW_AT_abstract_origin
.byte 19 # DW_FORM_ref4
.byte 17 # DW_AT_low_pc
.byte 27 # DW_FORM_addrx
.byte 18 # DW_AT_high_pc
.byte 6 # DW_FORM_data4
.byte 88 # DW_AT_call_file
.byte 11 # DW_FORM_data1
.byte 89 # DW_AT_call_line
.byte 11 # DW_FORM_data1
.byte 87 # DW_AT_call_column
.byte 11 # DW_FORM_data1
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 0 # EOM(3)
.section .debug_info,"",@progbits
.Lcu_begin0:
.long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
.Ldebug_info_start0:
.short 5 # DWARF version number
.byte 1 # DWARF Unit Type
.byte 8 # Address Size (in bytes)
.long .debug_abbrev # Offset Into Abbrev. Section
.byte 1 # Abbrev [1] 0xc:0x83 DW_TAG_compile_unit
.byte 0 # DW_AT_producer
.short 33 # DW_AT_language
.byte 1 # DW_AT_name
.long .Lstr_offsets_base0 # DW_AT_str_offsets_base
.long .Lline_table_start0 # DW_AT_stmt_list
.byte 2 # DW_AT_comp_dir
.byte 1 # DW_AT_low_pc
.long .Lfunc_end1-.Lfunc_begin0 # DW_AT_high_pc
.long .Laddr_table_base0 # DW_AT_addr_base
.long .Lloclists_table_base0 # DW_AT_loclists_base
.byte 2 # Abbrev [2] 0x27:0xb DW_TAG_variable
.byte 3 # DW_AT_name
.long 50 # DW_AT_type
# DW_AT_external
.byte 0 # DW_AT_decl_file
.byte 1 # DW_AT_decl_line
.byte 2 # DW_AT_location
.byte 161
.byte 0
.byte 3 # Abbrev [3] 0x32:0x4 DW_TAG_base_type
.byte 4 # DW_AT_name
.byte 5 # DW_AT_encoding
.byte 4 # DW_AT_byte_size
.byte 4 # Abbrev [4] 0x36:0x14 DW_TAG_subprogram
.byte 1 # DW_AT_low_pc
.long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
.byte 1 # DW_AT_frame_base
.byte 87
# DW_AT_call_all_calls
.long 74 # DW_AT_abstract_origin
.byte 5 # Abbrev [5] 0x42:0x7 DW_TAG_formal_parameter
.byte 1 # DW_AT_location
.byte 85
.long 79 # DW_AT_abstract_origin
.byte 0 # End Of Children Mark
.byte 6 # Abbrev [6] 0x4a:0xe DW_TAG_subprogram
.byte 5 # DW_AT_linkage_name
.byte 6 # DW_AT_name
.byte 0 # DW_AT_decl_file
.byte 2 # DW_AT_decl_line
# DW_AT_external
# DW_AT_inline
.byte 7 # Abbrev [7] 0x4f:0x8 DW_TAG_formal_parameter
.byte 7 # DW_AT_name
.byte 0 # DW_AT_decl_file
.byte 2 # DW_AT_decl_line
.long 88 # DW_AT_type
.byte 0 # End Of Children Mark
.byte 8 # Abbrev [8] 0x58:0x5 DW_TAG_pointer_type
.long 50 # DW_AT_type
.byte 9 # Abbrev [9] 0x5d:0x31 DW_TAG_subprogram
.byte 2 # DW_AT_low_pc
.long .Lfunc_end1-.Lfunc_begin1 # DW_AT_high_pc
.byte 1 # DW_AT_frame_base
.byte 87
# DW_AT_call_all_calls
.byte 8 # DW_AT_linkage_name
.byte 9 # DW_AT_name
.byte 0 # DW_AT_decl_file
.byte 6 # DW_AT_decl_line
.long 50 # DW_AT_type
# DW_AT_external
.byte 10 # Abbrev [10] 0x6d:0xa DW_TAG_formal_parameter
.byte 1 # DW_AT_location
.byte 85
.byte 10 # DW_AT_name
.byte 0 # DW_AT_decl_file
.byte 6 # DW_AT_decl_line
.long 50 # DW_AT_type
.byte 11 # Abbrev [11] 0x77:0x9 DW_TAG_variable
.byte 0 # DW_AT_location
.byte 7 # DW_AT_name
.byte 0 # DW_AT_decl_file
.byte 7 # DW_AT_decl_line
.long 50 # DW_AT_type
.byte 12 # Abbrev [12] 0x80:0xd DW_TAG_inlined_subroutine
.long 74 # DW_AT_abstract_origin
.byte 2 # DW_AT_low_pc
.long .Ltmp1-.Lfunc_begin1 # DW_AT_high_pc
.byte 0 # DW_AT_call_file
.byte 8 # DW_AT_call_line
.byte 4 # DW_AT_call_column
.byte 0 # End Of Children Mark
.byte 0 # End Of Children Mark
.Ldebug_info_end0:
.section .debug_str_offsets,"",@progbits
.long 48 # Length of String Offsets Set
.short 5
.short 0
.Lstr_offsets_base0:
.section .debug_str,"MS",@progbits,1
.Linfo_string0:
.asciz "clang version 15.0.0)" # string offset=0
.Linfo_string1:
.asciz "foo.cpp" # string offset=134
.Linfo_string2:
.asciz "/testLocListMultiple" # string offset=142
.Linfo_string3:
.asciz "fooVar" # string offset=199
.Linfo_string4:
.asciz "int" # string offset=206
.Linfo_string5:
.asciz "_Z6useFooPi" # string offset=210
.Linfo_string6:
.asciz "useFoo" # string offset=222
.Linfo_string7:
.asciz "x" # string offset=229
.Linfo_string8:
.asciz "_Z3fooi" # string offset=231
.Linfo_string9:
.asciz "foo" # string offset=239
.Linfo_string10:
.asciz "argc" # string offset=243
.section .debug_str_offsets,"",@progbits
.long .Linfo_string0
.long .Linfo_string1
.long .Linfo_string2
.long .Linfo_string3
.long .Linfo_string4
.long .Linfo_string5
.long .Linfo_string6
.long .Linfo_string7
.long .Linfo_string8
.long .Linfo_string9
.long .Linfo_string10
.section .debug_addr,"",@progbits
.long .Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution
.Ldebug_addr_start0:
.short 5 # DWARF version number
.byte 8 # Address size
.byte 0 # Segment selector size
.Laddr_table_base0:
.quad fooVar
.quad .Lfunc_begin0
.quad .Lfunc_begin1
.Ldebug_addr_end0:
.ident "clang version 15.0.0"
.section ".note.GNU-stack","",@progbits
.addrsig
.section .debug_line,"",@progbits
.Lline_table_start0:

View File

@ -0,0 +1,394 @@
# clang++ main.cpp -g -O2 -S
# void use(int * x, int * y) {
# *x += 4;
# *y -= 2;
# }
#
# extern int fooVar;
# int main(int argc, char *argv[]) {
# int x = argc;
# int y = fooVar + 3;
# use(&x, &y);
# return x + y;
# }
.text
.file "main.cpp"
.globl _Z3usePiS_ # -- Begin function _Z3usePiS_
.p2align 4, 0x90
.type _Z3usePiS_,@function
_Z3usePiS_: # @_Z3usePiS_
.Lfunc_begin0:
.file 0 "/testLocListMultiple" "main.cpp" md5 0xb1a1551182284263b0faa0cae08277da
.loc 0 1 0 # main.cpp:1:0
.cfi_startproc
# %bb.0: # %entry
#DEBUG_VALUE: use:x <- $rdi
#DEBUG_VALUE: use:y <- $rsi
.loc 0 2 4 prologue_end # main.cpp:2:4
addl $4, (%rdi)
.loc 0 3 4 # main.cpp:3:4
addl $-2, (%rsi)
.loc 0 4 1 # main.cpp:4:1
retq
.Ltmp0:
.Lfunc_end0:
.size _Z3usePiS_, .Lfunc_end0-_Z3usePiS_
.cfi_endproc
# -- End function
.globl main # -- Begin function main
.p2align 4, 0x90
.type main,@function
main: # @main
.Lfunc_begin1:
.loc 0 7 0 # main.cpp:7:0
.cfi_startproc
# %bb.0: # %entry
#DEBUG_VALUE: main:argc <- $edi
#DEBUG_VALUE: main:argv <- $rsi
#DEBUG_VALUE: main:x <- $edi
# kill: def $edi killed $edi def $rdi
.loc 0 9 12 prologue_end # main.cpp:9:12
movl fooVar(%rip), %eax
.Ltmp1:
#DEBUG_VALUE: main:y <- [DW_OP_plus_uconst 3, DW_OP_stack_value] $eax
#DEBUG_VALUE: main:y <- [DW_OP_plus_uconst 1, DW_OP_stack_value] $eax
#DEBUG_VALUE: main:x <- [DW_OP_plus_uconst 4, DW_OP_stack_value] $edi
.loc 0 11 13 # main.cpp:11:13
addl %edi, %eax
.Ltmp2:
addl $5, %eax
.loc 0 11 4 is_stmt 0 # main.cpp:11:4
retq
.Ltmp3:
.Lfunc_end1:
.size main, .Lfunc_end1-main
.cfi_endproc
# -- End function
.section .debug_loclists,"",@progbits
.long .Ldebug_list_header_end0-.Ldebug_list_header_start0 # Length
.Ldebug_list_header_start0:
.short 5 # Version
.byte 8 # Address size
.byte 0 # Segment selector size
.long 2 # Offset entry count
.Lloclists_table_base0:
.long .Ldebug_loc0-.Lloclists_table_base0
.long .Ldebug_loc1-.Lloclists_table_base0
.Ldebug_loc0:
.byte 4 # DW_LLE_offset_pair
.uleb128 .Lfunc_begin1-.Lfunc_begin0 # starting offset
.uleb128 .Ltmp1-.Lfunc_begin0 # ending offset
.byte 1 # Loc expr size
.byte 85 # super-register DW_OP_reg5
.byte 4 # DW_LLE_offset_pair
.uleb128 .Ltmp1-.Lfunc_begin0 # starting offset
.uleb128 .Lfunc_end1-.Lfunc_begin0 # ending offset
.byte 10 # Loc expr size
.byte 117 # DW_OP_breg5
.byte 4 # 4
.byte 16 # DW_OP_constu
.byte 255 # 4294967295
.byte 255 #
.byte 255 #
.byte 255 #
.byte 15 #
.byte 26 # DW_OP_and
.byte 159 # DW_OP_stack_value
.byte 0 # DW_LLE_end_of_list
.Ldebug_loc1:
.byte 4 # DW_LLE_offset_pair
.uleb128 .Ltmp1-.Lfunc_begin0 # starting offset
.uleb128 .Ltmp2-.Lfunc_begin0 # ending offset
.byte 10 # Loc expr size
.byte 112 # DW_OP_breg0
.byte 1 # 1
.byte 16 # DW_OP_constu
.byte 255 # 4294967295
.byte 255 #
.byte 255 #
.byte 255 #
.byte 15 #
.byte 26 # DW_OP_and
.byte 159 # DW_OP_stack_value
.byte 0 # DW_LLE_end_of_list
.Ldebug_list_header_end0:
.section .debug_abbrev,"",@progbits
.byte 1 # Abbreviation Code
.byte 17 # DW_TAG_compile_unit
.byte 1 # DW_CHILDREN_yes
.byte 37 # DW_AT_producer
.byte 37 # DW_FORM_strx1
.byte 19 # DW_AT_language
.byte 5 # DW_FORM_data2
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 114 # DW_AT_str_offsets_base
.byte 23 # DW_FORM_sec_offset
.byte 16 # DW_AT_stmt_list
.byte 23 # DW_FORM_sec_offset
.byte 27 # DW_AT_comp_dir
.byte 37 # DW_FORM_strx1
.byte 17 # DW_AT_low_pc
.byte 27 # DW_FORM_addrx
.byte 18 # DW_AT_high_pc
.byte 6 # DW_FORM_data4
.byte 115 # DW_AT_addr_base
.byte 23 # DW_FORM_sec_offset
.ascii "\214\001" # DW_AT_loclists_base
.byte 23 # DW_FORM_sec_offset
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 2 # Abbreviation Code
.byte 46 # DW_TAG_subprogram
.byte 1 # DW_CHILDREN_yes
.byte 17 # DW_AT_low_pc
.byte 27 # DW_FORM_addrx
.byte 18 # DW_AT_high_pc
.byte 6 # DW_FORM_data4
.byte 64 # DW_AT_frame_base
.byte 24 # DW_FORM_exprloc
.byte 122 # DW_AT_call_all_calls
.byte 25 # DW_FORM_flag_present
.byte 110 # DW_AT_linkage_name
.byte 37 # DW_FORM_strx1
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 58 # DW_AT_decl_file
.byte 11 # DW_FORM_data1
.byte 59 # DW_AT_decl_line
.byte 11 # DW_FORM_data1
.byte 63 # DW_AT_external
.byte 25 # DW_FORM_flag_present
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 3 # Abbreviation Code
.byte 5 # DW_TAG_formal_parameter
.byte 0 # DW_CHILDREN_no
.byte 2 # DW_AT_location
.byte 24 # DW_FORM_exprloc
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 58 # DW_AT_decl_file
.byte 11 # DW_FORM_data1
.byte 59 # DW_AT_decl_line
.byte 11 # DW_FORM_data1
.byte 73 # DW_AT_type
.byte 19 # DW_FORM_ref4
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 4 # Abbreviation Code
.byte 46 # DW_TAG_subprogram
.byte 1 # DW_CHILDREN_yes
.byte 17 # DW_AT_low_pc
.byte 27 # DW_FORM_addrx
.byte 18 # DW_AT_high_pc
.byte 6 # DW_FORM_data4
.byte 64 # DW_AT_frame_base
.byte 24 # DW_FORM_exprloc
.byte 122 # DW_AT_call_all_calls
.byte 25 # DW_FORM_flag_present
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 58 # DW_AT_decl_file
.byte 11 # DW_FORM_data1
.byte 59 # DW_AT_decl_line
.byte 11 # DW_FORM_data1
.byte 73 # DW_AT_type
.byte 19 # DW_FORM_ref4
.byte 63 # DW_AT_external
.byte 25 # DW_FORM_flag_present
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 5 # Abbreviation Code
.byte 52 # DW_TAG_variable
.byte 0 # DW_CHILDREN_no
.byte 2 # DW_AT_location
.byte 34 # DW_FORM_loclistx
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 58 # DW_AT_decl_file
.byte 11 # DW_FORM_data1
.byte 59 # DW_AT_decl_line
.byte 11 # DW_FORM_data1
.byte 73 # DW_AT_type
.byte 19 # DW_FORM_ref4
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 6 # Abbreviation Code
.byte 36 # DW_TAG_base_type
.byte 0 # DW_CHILDREN_no
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 62 # DW_AT_encoding
.byte 11 # DW_FORM_data1
.byte 11 # DW_AT_byte_size
.byte 11 # DW_FORM_data1
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 7 # Abbreviation Code
.byte 15 # DW_TAG_pointer_type
.byte 0 # DW_CHILDREN_no
.byte 73 # DW_AT_type
.byte 19 # DW_FORM_ref4
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 0 # EOM(3)
.section .debug_info,"",@progbits
.Lcu_begin0:
.long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
.Ldebug_info_start0:
.short 5 # DWARF version number
.byte 1 # DWARF Unit Type
.byte 8 # Address Size (in bytes)
.long .debug_abbrev # Offset Into Abbrev. Section
.byte 1 # Abbrev [1] 0xc:0x8a DW_TAG_compile_unit
.byte 0 # DW_AT_producer
.short 33 # DW_AT_language
.byte 1 # DW_AT_name
.long .Lstr_offsets_base0 # DW_AT_str_offsets_base
.long .Lline_table_start0 # DW_AT_stmt_list
.byte 2 # DW_AT_comp_dir
.byte 0 # DW_AT_low_pc
.long .Lfunc_end1-.Lfunc_begin0 # DW_AT_high_pc
.long .Laddr_table_base0 # DW_AT_addr_base
.long .Lloclists_table_base0 # DW_AT_loclists_base
.byte 2 # Abbrev [2] 0x27:0x21 DW_TAG_subprogram
.byte 0 # DW_AT_low_pc
.long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
.byte 1 # DW_AT_frame_base
.byte 87
# DW_AT_call_all_calls
.byte 3 # DW_AT_linkage_name
.byte 4 # DW_AT_name
.byte 0 # DW_AT_decl_file
.byte 1 # DW_AT_decl_line
# DW_AT_external
.byte 3 # Abbrev [3] 0x33:0xa DW_TAG_formal_parameter
.byte 1 # DW_AT_location
.byte 85
.byte 7 # DW_AT_name
.byte 0 # DW_AT_decl_file
.byte 1 # DW_AT_decl_line
.long 130 # DW_AT_type
.byte 3 # Abbrev [3] 0x3d:0xa DW_TAG_formal_parameter
.byte 1 # DW_AT_location
.byte 84
.byte 8 # DW_AT_name
.byte 0 # DW_AT_decl_file
.byte 1 # DW_AT_decl_line
.long 130 # DW_AT_type
.byte 0 # End Of Children Mark
.byte 4 # Abbrev [4] 0x48:0x36 DW_TAG_subprogram
.byte 1 # DW_AT_low_pc
.long .Lfunc_end1-.Lfunc_begin1 # DW_AT_high_pc
.byte 1 # DW_AT_frame_base
.byte 87
# DW_AT_call_all_calls
.byte 5 # DW_AT_name
.byte 0 # DW_AT_decl_file
.byte 7 # DW_AT_decl_line
.long 126 # DW_AT_type
# DW_AT_external
.byte 3 # Abbrev [3] 0x57:0xa DW_TAG_formal_parameter
.byte 1 # DW_AT_location
.byte 85
.byte 9 # DW_AT_name
.byte 0 # DW_AT_decl_file
.byte 7 # DW_AT_decl_line
.long 126 # DW_AT_type
.byte 3 # Abbrev [3] 0x61:0xa DW_TAG_formal_parameter
.byte 1 # DW_AT_location
.byte 84
.byte 10 # DW_AT_name
.byte 0 # DW_AT_decl_file
.byte 7 # DW_AT_decl_line
.long 135 # DW_AT_type
.byte 5 # Abbrev [5] 0x6b:0x9 DW_TAG_variable
.byte 0 # DW_AT_location
.byte 7 # DW_AT_name
.byte 0 # DW_AT_decl_file
.byte 8 # DW_AT_decl_line
.long 126 # DW_AT_type
.byte 5 # Abbrev [5] 0x74:0x9 DW_TAG_variable
.byte 1 # DW_AT_location
.byte 8 # DW_AT_name
.byte 0 # DW_AT_decl_file
.byte 9 # DW_AT_decl_line
.long 126 # DW_AT_type
.byte 0 # End Of Children Mark
.byte 6 # Abbrev [6] 0x7e:0x4 DW_TAG_base_type
.byte 6 # DW_AT_name
.byte 5 # DW_AT_encoding
.byte 4 # DW_AT_byte_size
.byte 7 # Abbrev [7] 0x82:0x5 DW_TAG_pointer_type
.long 126 # DW_AT_type
.byte 7 # Abbrev [7] 0x87:0x5 DW_TAG_pointer_type
.long 140 # DW_AT_type
.byte 7 # Abbrev [7] 0x8c:0x5 DW_TAG_pointer_type
.long 145 # DW_AT_type
.byte 6 # Abbrev [6] 0x91:0x4 DW_TAG_base_type
.byte 11 # DW_AT_name
.byte 6 # DW_AT_encoding
.byte 1 # DW_AT_byte_size
.byte 0 # End Of Children Mark
.Ldebug_info_end0:
.section .debug_str_offsets,"",@progbits
.long 52 # Length of String Offsets Set
.short 5
.short 0
.Lstr_offsets_base0:
.section .debug_str,"MS",@progbits,1
.Linfo_string0:
.asciz "clang version 15.0.0" # string offset=0
.Linfo_string1:
.asciz "main.cpp" # string offset=134
.Linfo_string2:
.asciz "/testLocListMultiple" # string offset=143
.Linfo_string3:
.asciz "_Z3usePiS_" # string offset=200
.Linfo_string4:
.asciz "use" # string offset=211
.Linfo_string5:
.asciz "main" # string offset=215
.Linfo_string6:
.asciz "int" # string offset=220
.Linfo_string7:
.asciz "x" # string offset=224
.Linfo_string8:
.asciz "y" # string offset=226
.Linfo_string9:
.asciz "argc" # string offset=228
.Linfo_string10:
.asciz "argv" # string offset=233
.Linfo_string11:
.asciz "char" # string offset=238
.section .debug_str_offsets,"",@progbits
.long .Linfo_string0
.long .Linfo_string1
.long .Linfo_string2
.long .Linfo_string3
.long .Linfo_string4
.long .Linfo_string5
.long .Linfo_string6
.long .Linfo_string7
.long .Linfo_string8
.long .Linfo_string9
.long .Linfo_string10
.long .Linfo_string11
.section .debug_addr,"",@progbits
.long .Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution
.Ldebug_addr_start0:
.short 5 # DWARF version number
.byte 8 # Address size
.byte 0 # Segment selector size
.Laddr_table_base0:
.quad .Lfunc_begin0
.quad .Lfunc_begin1
.Ldebug_addr_end0:
.ident "clang version 15.0.0"
.section ".note.GNU-stack","",@progbits
.addrsig
.section .debug_line,"",@progbits
.Lline_table_start0:

View File

@ -0,0 +1,167 @@
# REQUIRES: system-linux
# RUN: llvm-mc -dwarf-version=4 -filetype=obj -triple x86_64-unknown-linux %s -o %t1.o
# RUN: %clang %cflags -dwarf-5 %t1.o -o %t.exe -Wl,-q
# RUN: llvm-bolt %t.exe -o %t.bolt -update-debug-sections
# RUN: llvm-dwarfdump --show-form --verbose --debug-line %t.exe | FileCheck --check-prefix=PRECHECK %s
# RUN: llvm-dwarfdump --show-form --verbose --debug-line %t.bolt | FileCheck --check-prefix=POSTCHECK %s
# This test checks that .debug_line gets generated correctly when .debug_info is DWARF5, and .debug_line is DWARF4.
# PRECHECK: version: 4
# PRECHECK: file_names[ 1]:
# PRECHECK-NEXT: name: "main.cpp"
# PRECHECK-NEXT: dir_index: 0
# PRECHECK-NEXT: mod_time: 0x00000000
# PRECHECK-NEXT: length: 0x00000000
# POSTCHECK: version: 4
# POSTCHECK: file_names[ 1]:
# POSTCHECK-NEXT: name: "main.cpp"
# POSTCHECK-NEXT: dir_index: 0
# POSTCHECK-NEXT: mod_time: 0x00000000
# POSTCHECK-NEXT: length: 0x00000000
# int main() {
# return 0;
# }
.file "main.cpp"
.text
.Ltext0:
.globl main
.type main, @function
main:
.LFB0:
.file 1 "main.cpp"
.loc 1 1 12
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
.loc 1 2 10
movl $0, %eax
.loc 1 3 1
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.Letext0:
.section .debug_info,"",@progbits
.Ldebug_info0:
.long 0x50
.value 0x5
.byte 0x1
.byte 0x8
.long .Ldebug_abbrev0
.uleb128 0x1
.long .LASF0
.byte 0x21
.long .LASF1
.long .LASF2
.quad .Ltext0
.quad .Letext0-.Ltext0
.long .Ldebug_line0
.uleb128 0x2
.long .LASF3
.byte 0x1
.byte 0x1
.byte 0x5
.long 0x4c
.quad .LFB0
.quad .LFE0-.LFB0
.uleb128 0x1
.byte 0x9c
.uleb128 0x3
.byte 0x4
.byte 0x5
.string "int"
.byte 0
.section .debug_abbrev,"",@progbits
.Ldebug_abbrev0:
.uleb128 0x1
.uleb128 0x11
.byte 0x1
.uleb128 0x25
.uleb128 0xe
.uleb128 0x13
.uleb128 0xb
.uleb128 0x3
.uleb128 0xe
.uleb128 0x1b
.uleb128 0xe
.uleb128 0x11
.uleb128 0x1
.uleb128 0x12
.uleb128 0x7
.uleb128 0x10
.uleb128 0x17
.byte 0
.byte 0
.uleb128 0x2
.uleb128 0x2e
.byte 0
.uleb128 0x3f
.uleb128 0x19
.uleb128 0x3
.uleb128 0xe
.uleb128 0x3a
.uleb128 0xb
.uleb128 0x3b
.uleb128 0xb
.uleb128 0x39
.uleb128 0xb
.uleb128 0x49
.uleb128 0x13
.uleb128 0x11
.uleb128 0x1
.uleb128 0x12
.uleb128 0x7
.uleb128 0x40
.uleb128 0x18
.uleb128 0x7a
.uleb128 0x19
.byte 0
.byte 0
.uleb128 0x3
.uleb128 0x24
.byte 0
.uleb128 0xb
.uleb128 0xb
.uleb128 0x3e
.uleb128 0xb
.uleb128 0x3
.uleb128 0x8
.byte 0
.byte 0
.byte 0
.section .debug_aranges,"",@progbits
.long 0x2c
.value 0x2
.long .Ldebug_info0
.byte 0x8
.byte 0
.value 0
.value 0
.quad .Ltext0
.quad .Letext0-.Ltext0
.quad 0
.quad 0
.section .debug_line,"",@progbits
.Ldebug_line0:
.section .debug_str,"MS",@progbits,1
.LASF0:
.string "GNU C++14 8.5.0 20210514 (Red Hat 8.5.0-3) -mtune=generic -march=x86-64 -g2 -gdwarf-5"
.LASF1:
.string "main.cpp"
.LASF3:
.string "main"
.LASF2:
.string "."
.ident "GCC: (GNU) 8.5.0 20210514 (Red Hat 8.5.0-3)"
.section .note.GNU-stack,"",@progbits

View File

@ -0,0 +1,185 @@
# REQUIRES: system-linux
# RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %s -o %t1.o
# RUN: %clang %cflags -dwarf-5 %t1.o -o %t.exe -Wl,-q
# RUN: llvm-bolt %t.exe -o %t.bolt -update-debug-sections
# RUN: llvm-dwarfdump --show-form --verbose --debug-line %t.exe | FileCheck --check-prefix=PRECHECK %s
# RUN: llvm-dwarfdump --show-form --verbose --debug-line %t.bolt | FileCheck --check-prefix=POSTCHECK %s
# This test checks that DWARF5 .debug_line is handled correctly.
# PRECHECK: version: 5
# PRECHECK: include_directories[ 0] = .debug_line_str[0x00000000]
# PRECHECK-NEXT: file_names[ 0]:
# PRECHECK-NEXT: name: .debug_line_str[0x00000002] = "main.cpp"
# PRECHECK-NEXT: dir_index: 0
# PRECHECK-NEXT: md5_checksum: bb12fec8d002b1f0e06f7dee4604c6cc
# PRECHECK-NOT: file_names[ 1]:
# POSTCHECK: version: 5
# POSTCHECK: include_directories[ 0] = .debug_line_str[0x00000000]
# POSTCHECK-NEXT: file_names[ 0]:
# POSTCHECK-NEXT: name: .debug_line_str[0x00000002] = "main.cpp"
# POSTCHECK-NEXT: dir_index: 0
# POSTCHECK-NEXT: md5_checksum: bb12fec8d002b1f0e06f7dee4604c6cc
# POSTCHECK-NOT: file_names[ 1]:
# int main() {
# return 0;
# }
.text
.file "main.cpp"
.globl main # -- Begin function main
.p2align 4, 0x90
.type main,@function
main: # @main
.Lfunc_begin0:
.file 0 "." "main.cpp" md5 0xbb12fec8d002b1f0e06f7dee4604c6cc
.loc 0 1 0 # main.cpp:1:0
.cfi_startproc
# %bb.0: # %entry
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
movl $0, -4(%rbp)
.Ltmp0:
.loc 0 2 3 prologue_end # main.cpp:2:3
xorl %eax, %eax
popq %rbp
.cfi_def_cfa %rsp, 8
retq
.Ltmp1:
.Lfunc_end0:
.size main, .Lfunc_end0-main
.cfi_endproc
# -- End function
.section .debug_abbrev,"",@progbits
.byte 1 # Abbreviation Code
.byte 17 # DW_TAG_compile_unit
.byte 1 # DW_CHILDREN_yes
.byte 37 # DW_AT_producer
.byte 37 # DW_FORM_strx1
.byte 19 # DW_AT_language
.byte 5 # DW_FORM_data2
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 114 # DW_AT_str_offsets_base
.byte 23 # DW_FORM_sec_offset
.byte 16 # DW_AT_stmt_list
.byte 23 # DW_FORM_sec_offset
.byte 27 # DW_AT_comp_dir
.byte 37 # DW_FORM_strx1
.byte 17 # DW_AT_low_pc
.byte 27 # DW_FORM_addrx
.byte 18 # DW_AT_high_pc
.byte 6 # DW_FORM_data4
.byte 115 # DW_AT_addr_base
.byte 23 # DW_FORM_sec_offset
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 2 # Abbreviation Code
.byte 46 # DW_TAG_subprogram
.byte 0 # DW_CHILDREN_no
.byte 17 # DW_AT_low_pc
.byte 27 # DW_FORM_addrx
.byte 18 # DW_AT_high_pc
.byte 6 # DW_FORM_data4
.byte 64 # DW_AT_frame_base
.byte 24 # DW_FORM_exprloc
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 58 # DW_AT_decl_file
.byte 11 # DW_FORM_data1
.byte 59 # DW_AT_decl_line
.byte 11 # DW_FORM_data1
.byte 73 # DW_AT_type
.byte 19 # DW_FORM_ref4
.byte 63 # DW_AT_external
.byte 25 # DW_FORM_flag_present
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 3 # Abbreviation Code
.byte 36 # DW_TAG_base_type
.byte 0 # DW_CHILDREN_no
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 62 # DW_AT_encoding
.byte 11 # DW_FORM_data1
.byte 11 # DW_AT_byte_size
.byte 11 # DW_FORM_data1
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 0 # EOM(3)
.section .debug_info,"",@progbits
.Lcu_begin0:
.long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
.Ldebug_info_start0:
.short 5 # DWARF version number
.byte 1 # DWARF Unit Type
.byte 8 # Address Size (in bytes)
.long .debug_abbrev # Offset Into Abbrev. Section
.byte 1 # Abbrev [1] 0xc:0x2b DW_TAG_compile_unit
.byte 0 # DW_AT_producer
.short 33 # DW_AT_language
.byte 1 # DW_AT_name
.long .Lstr_offsets_base0 # DW_AT_str_offsets_base
.long .Lline_table_start0 # DW_AT_stmt_list
.byte 2 # DW_AT_comp_dir
.byte 0 # DW_AT_low_pc
.long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
.long .Laddr_table_base0 # DW_AT_addr_base
.byte 2 # Abbrev [2] 0x23:0xf DW_TAG_subprogram
.byte 0 # DW_AT_low_pc
.long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
.byte 1 # DW_AT_frame_base
.byte 86
.byte 3 # DW_AT_name
.byte 0 # DW_AT_decl_file
.byte 1 # DW_AT_decl_line
.long 50 # DW_AT_type
# DW_AT_external
.byte 3 # Abbrev [3] 0x32:0x4 DW_TAG_base_type
.byte 4 # DW_AT_name
.byte 5 # DW_AT_encoding
.byte 4 # DW_AT_byte_size
.byte 0 # End Of Children Mark
.Ldebug_info_end0:
.section .debug_str_offsets,"",@progbits
.long 24 # Length of String Offsets Set
.short 5
.short 0
.Lstr_offsets_base0:
.section .debug_str,"MS",@progbits,1
.Linfo_string0:
.asciz "clang version 15.0.0" # string offset=0
.Linfo_string1:
.asciz "main.cpp" # string offset=134
.Linfo_string2:
.asciz "." # string offset=143
.Linfo_string3:
.asciz "main" # string offset=180
.Linfo_string4:
.asciz "int" # string offset=185
.section .debug_str_offsets,"",@progbits
.long .Linfo_string0
.long .Linfo_string1
.long .Linfo_string2
.long .Linfo_string3
.long .Linfo_string4
.section .debug_addr,"",@progbits
.long .Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution
.Ldebug_addr_start0:
.short 5 # DWARF version number
.byte 8 # Address size
.byte 0 # Segment selector size
.Laddr_table_base0:
.quad .Lfunc_begin0
.Ldebug_addr_end0:
.ident "clang version 15.0.0"
.section ".note.GNU-stack","",@progbits
.addrsig
.section .debug_line,"",@progbits
.Lline_table_start0:

View File

@ -0,0 +1,439 @@
# REQUIRES: system-linux
# RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %s -o %t1.o
# RUN: %clang %cflags -dwarf-5 %t1.o -o %t.exe -Wl,-q
# RUN: llvm-bolt %t.exe -o %t.bolt -update-debug-sections
# RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.exe | FileCheck --check-prefix=PRECHECK %s
# RUN: llvm-dwarfdump --show-form --verbose --debug-addr %t.bolt > %t.txt
# RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt >> %t.txt
# RUN: cat %t.txt | FileCheck --check-prefix=POSTCHECK %s
# This tests checks that re-writing of .debug_loclists is handled correctly.
# PRECHECK: version = 0x0005
# PRECHECK: DW_AT_loclists_base [DW_FORM_sec_offset] (0x0000000c)
# PRECHECK-EMPTY:
# PRECHECK: DW_TAG_variable
# PRECHECK: DW_AT_location [DW_FORM_loclistx]
# PRECHECK-SAME: indexed (0x0)
# PRECHECK-SAME: loclist = 0x00000010
# POSTCHECK: Addrs: [
# POSTCHECK-NEXT: 0x
# POSTCHECK-NEXT: 0x[[#%.16x,ADDR:]]
# POSTCHECK-NEXT: 0x
# POSTCHECK-NEXT: 0x[[#%.16x,ADDR2:]]
# POSTCHECK: version = 0x0005
# POSTCHECK: DW_AT_loclists_base [DW_FORM_sec_offset] (0x0000000c)
# POSTCHECK: DW_AT_rnglists_base [DW_FORM_sec_offset] (0x0000000c)
# POSTCHECK: DW_TAG_variable
# POSTCHECK: DW_AT_location [DW_FORM_loclistx]
# POSTCHECK-SAME: indexed (0x0)
# POSTCHECK-SAME: loclist = 0x00000010
# POSTCHECK-NEXT: [0x[[#ADDR]]
# POSTCHECK-SAME: 0x[[#ADDR + 3]]
# POSTCHECK-NEXT: [0x[[#ADDR2]]
# POSTCHECK-SAME: 0x[[#ADDR2 + 1]]
# clang++ main.cpp -g -O2 -S
# void use(int * x) {
# *x += 4;
# }
#
# int main(int argc, char *argv[]) {
# int x = argc;
# use(&x);
# return x;
# }
.text
.file "main.cpp"
.globl _Z3usePi # -- Begin function _Z3usePi
.p2align 4, 0x90
.type _Z3usePi,@function
_Z3usePi: # @_Z3usePi
.Lfunc_begin0:
.file 0 "testLocList" "main.cpp" md5 0x95a77c95663d823a6228bf928825e8c7
.loc 0 1 0 # main.cpp:1:0
.cfi_startproc
# %bb.0: # %entry
#DEBUG_VALUE: use:x <- $rdi
.loc 0 2 4 prologue_end # main.cpp:2:4
addl $4, (%rdi)
.loc 0 3 1 # main.cpp:3:1
retq
.Ltmp0:
.Lfunc_end0:
.size _Z3usePi, .Lfunc_end0-_Z3usePi
.cfi_endproc
# -- End function
.globl main # -- Begin function main
.p2align 4, 0x90
.type main,@function
main: # @main
.Lfunc_begin1:
.loc 0 5 0 # main.cpp:5:0
.cfi_startproc
# %bb.0: # %entry
#DEBUG_VALUE: main:argc <- $edi
#DEBUG_VALUE: main:argv <- $rsi
#DEBUG_VALUE: main:x <- $edi
# kill: def $edi killed $edi def $rdi
#DEBUG_VALUE: use:x <- undef
.loc 0 2 4 prologue_end # main.cpp:2:4
leal 4(%rdi), %eax
.Ltmp1:
#DEBUG_VALUE: main:x <- $eax
.loc 0 8 4 # main.cpp:8:4
retq
.Ltmp2:
.Lfunc_end1:
.size main, .Lfunc_end1-main
.cfi_endproc
# -- End function
.section .debug_loclists,"",@progbits
.long .Ldebug_list_header_end0-.Ldebug_list_header_start0 # Length
.Ldebug_list_header_start0:
.short 5 # Version
.byte 8 # Address size
.byte 0 # Segment selector size
.long 1 # Offset entry count
.Lloclists_table_base0:
.long .Ldebug_loc0-.Lloclists_table_base0
.Ldebug_loc0:
.byte 4 # DW_LLE_offset_pair
.uleb128 .Lfunc_begin1-.Lfunc_begin0 # starting offset
.uleb128 .Ltmp1-.Lfunc_begin0 # ending offset
.byte 1 # Loc expr size
.byte 85 # super-register DW_OP_reg5
.byte 4 # DW_LLE_offset_pair
.uleb128 .Ltmp1-.Lfunc_begin0 # starting offset
.uleb128 .Lfunc_end1-.Lfunc_begin0 # ending offset
.byte 1 # Loc expr size
.byte 80 # super-register DW_OP_reg0
.byte 0 # DW_LLE_end_of_list
.Ldebug_list_header_end0:
.section .debug_abbrev,"",@progbits
.byte 1 # Abbreviation Code
.byte 17 # DW_TAG_compile_unit
.byte 1 # DW_CHILDREN_yes
.byte 37 # DW_AT_producer
.byte 37 # DW_FORM_strx1
.byte 19 # DW_AT_language
.byte 5 # DW_FORM_data2
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 114 # DW_AT_str_offsets_base
.byte 23 # DW_FORM_sec_offset
.byte 16 # DW_AT_stmt_list
.byte 23 # DW_FORM_sec_offset
.byte 27 # DW_AT_comp_dir
.byte 37 # DW_FORM_strx1
.byte 17 # DW_AT_low_pc
.byte 27 # DW_FORM_addrx
.byte 18 # DW_AT_high_pc
.byte 6 # DW_FORM_data4
.byte 115 # DW_AT_addr_base
.byte 23 # DW_FORM_sec_offset
.ascii "\214\001" # DW_AT_loclists_base
.byte 23 # DW_FORM_sec_offset
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 2 # Abbreviation Code
.byte 46 # DW_TAG_subprogram
.byte 1 # DW_CHILDREN_yes
.byte 17 # DW_AT_low_pc
.byte 27 # DW_FORM_addrx
.byte 18 # DW_AT_high_pc
.byte 6 # DW_FORM_data4
.byte 64 # DW_AT_frame_base
.byte 24 # DW_FORM_exprloc
.byte 122 # DW_AT_call_all_calls
.byte 25 # DW_FORM_flag_present
.byte 49 # DW_AT_abstract_origin
.byte 19 # DW_FORM_ref4
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 3 # Abbreviation Code
.byte 5 # DW_TAG_formal_parameter
.byte 0 # DW_CHILDREN_no
.byte 2 # DW_AT_location
.byte 24 # DW_FORM_exprloc
.byte 49 # DW_AT_abstract_origin
.byte 19 # DW_FORM_ref4
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 4 # Abbreviation Code
.byte 46 # DW_TAG_subprogram
.byte 1 # DW_CHILDREN_yes
.byte 110 # DW_AT_linkage_name
.byte 37 # DW_FORM_strx1
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 58 # DW_AT_decl_file
.byte 11 # DW_FORM_data1
.byte 59 # DW_AT_decl_line
.byte 11 # DW_FORM_data1
.byte 63 # DW_AT_external
.byte 25 # DW_FORM_flag_present
.byte 32 # DW_AT_inline
.byte 33 # DW_FORM_implicit_const
.byte 1
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 5 # Abbreviation Code
.byte 5 # DW_TAG_formal_parameter
.byte 0 # DW_CHILDREN_no
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 58 # DW_AT_decl_file
.byte 11 # DW_FORM_data1
.byte 59 # DW_AT_decl_line
.byte 11 # DW_FORM_data1
.byte 73 # DW_AT_type
.byte 19 # DW_FORM_ref4
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 6 # Abbreviation Code
.byte 15 # DW_TAG_pointer_type
.byte 0 # DW_CHILDREN_no
.byte 73 # DW_AT_type
.byte 19 # DW_FORM_ref4
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 7 # Abbreviation Code
.byte 36 # DW_TAG_base_type
.byte 0 # DW_CHILDREN_no
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 62 # DW_AT_encoding
.byte 11 # DW_FORM_data1
.byte 11 # DW_AT_byte_size
.byte 11 # DW_FORM_data1
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 8 # Abbreviation Code
.byte 46 # DW_TAG_subprogram
.byte 1 # DW_CHILDREN_yes
.byte 17 # DW_AT_low_pc
.byte 27 # DW_FORM_addrx
.byte 18 # DW_AT_high_pc
.byte 6 # DW_FORM_data4
.byte 64 # DW_AT_frame_base
.byte 24 # DW_FORM_exprloc
.byte 122 # DW_AT_call_all_calls
.byte 25 # DW_FORM_flag_present
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 58 # DW_AT_decl_file
.byte 11 # DW_FORM_data1
.byte 59 # DW_AT_decl_line
.byte 11 # DW_FORM_data1
.byte 73 # DW_AT_type
.byte 19 # DW_FORM_ref4
.byte 63 # DW_AT_external
.byte 25 # DW_FORM_flag_present
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 9 # Abbreviation Code
.byte 5 # DW_TAG_formal_parameter
.byte 0 # DW_CHILDREN_no
.byte 2 # DW_AT_location
.byte 24 # DW_FORM_exprloc
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 58 # DW_AT_decl_file
.byte 11 # DW_FORM_data1
.byte 59 # DW_AT_decl_line
.byte 11 # DW_FORM_data1
.byte 73 # DW_AT_type
.byte 19 # DW_FORM_ref4
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 10 # Abbreviation Code
.byte 52 # DW_TAG_variable
.byte 0 # DW_CHILDREN_no
.byte 2 # DW_AT_location
.byte 34 # DW_FORM_loclistx
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 58 # DW_AT_decl_file
.byte 11 # DW_FORM_data1
.byte 59 # DW_AT_decl_line
.byte 11 # DW_FORM_data1
.byte 73 # DW_AT_type
.byte 19 # DW_FORM_ref4
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 11 # Abbreviation Code
.byte 29 # DW_TAG_inlined_subroutine
.byte 0 # DW_CHILDREN_no
.byte 49 # DW_AT_abstract_origin
.byte 19 # DW_FORM_ref4
.byte 17 # DW_AT_low_pc
.byte 27 # DW_FORM_addrx
.byte 18 # DW_AT_high_pc
.byte 6 # DW_FORM_data4
.byte 88 # DW_AT_call_file
.byte 11 # DW_FORM_data1
.byte 89 # DW_AT_call_line
.byte 11 # DW_FORM_data1
.byte 87 # DW_AT_call_column
.byte 11 # DW_FORM_data1
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 0 # EOM(3)
.section .debug_info,"",@progbits
.Lcu_begin0:
.long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
.Ldebug_info_start0:
.short 5 # DWARF version number
.byte 1 # DWARF Unit Type
.byte 8 # Address Size (in bytes)
.long .debug_abbrev # Offset Into Abbrev. Section
.byte 1 # Abbrev [1] 0xc:0x8f DW_TAG_compile_unit
.byte 0 # DW_AT_producer
.short 33 # DW_AT_language
.byte 1 # DW_AT_name
.long .Lstr_offsets_base0 # DW_AT_str_offsets_base
.long .Lline_table_start0 # DW_AT_stmt_list
.byte 2 # DW_AT_comp_dir
.byte 0 # DW_AT_low_pc
.long .Lfunc_end1-.Lfunc_begin0 # DW_AT_high_pc
.long .Laddr_table_base0 # DW_AT_addr_base
.long .Lloclists_table_base0 # DW_AT_loclists_base
.byte 2 # Abbrev [2] 0x27:0x14 DW_TAG_subprogram
.byte 0 # DW_AT_low_pc
.long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
.byte 1 # DW_AT_frame_base
.byte 87
# DW_AT_call_all_calls
.long 59 # DW_AT_abstract_origin
.byte 3 # Abbrev [3] 0x33:0x7 DW_TAG_formal_parameter
.byte 1 # DW_AT_location
.byte 85
.long 64 # DW_AT_abstract_origin
.byte 0 # End Of Children Mark
.byte 4 # Abbrev [4] 0x3b:0xe DW_TAG_subprogram
.byte 3 # DW_AT_linkage_name
.byte 4 # DW_AT_name
.byte 0 # DW_AT_decl_file
.byte 1 # DW_AT_decl_line
# DW_AT_external
# DW_AT_inline
.byte 5 # Abbrev [5] 0x40:0x8 DW_TAG_formal_parameter
.byte 5 # DW_AT_name
.byte 0 # DW_AT_decl_file
.byte 1 # DW_AT_decl_line
.long 73 # DW_AT_type
.byte 0 # End Of Children Mark
.byte 6 # Abbrev [6] 0x49:0x5 DW_TAG_pointer_type
.long 78 # DW_AT_type
.byte 7 # Abbrev [7] 0x4e:0x4 DW_TAG_base_type
.byte 6 # DW_AT_name
.byte 5 # DW_AT_encoding
.byte 4 # DW_AT_byte_size
.byte 8 # Abbrev [8] 0x52:0x3a DW_TAG_subprogram
.byte 1 # DW_AT_low_pc
.long .Lfunc_end1-.Lfunc_begin1 # DW_AT_high_pc
.byte 1 # DW_AT_frame_base
.byte 87
# DW_AT_call_all_calls
.byte 7 # DW_AT_name
.byte 0 # DW_AT_decl_file
.byte 5 # DW_AT_decl_line
.long 78 # DW_AT_type
# DW_AT_external
.byte 9 # Abbrev [9] 0x61:0xa DW_TAG_formal_parameter
.byte 1 # DW_AT_location
.byte 85
.byte 8 # DW_AT_name
.byte 0 # DW_AT_decl_file
.byte 5 # DW_AT_decl_line
.long 78 # DW_AT_type
.byte 9 # Abbrev [9] 0x6b:0xa DW_TAG_formal_parameter
.byte 1 # DW_AT_location
.byte 84
.byte 9 # DW_AT_name
.byte 0 # DW_AT_decl_file
.byte 5 # DW_AT_decl_line
.long 140 # DW_AT_type
.byte 10 # Abbrev [10] 0x75:0x9 DW_TAG_variable
.byte 0 # DW_AT_location
.byte 5 # DW_AT_name
.byte 0 # DW_AT_decl_file
.byte 6 # DW_AT_decl_line
.long 78 # DW_AT_type
.byte 11 # Abbrev [11] 0x7e:0xd DW_TAG_inlined_subroutine
.long 59 # DW_AT_abstract_origin
.byte 1 # DW_AT_low_pc
.long .Ltmp1-.Lfunc_begin1 # DW_AT_high_pc
.byte 0 # DW_AT_call_file
.byte 7 # DW_AT_call_line
.byte 4 # DW_AT_call_column
.byte 0 # End Of Children Mark
.byte 6 # Abbrev [6] 0x8c:0x5 DW_TAG_pointer_type
.long 145 # DW_AT_type
.byte 6 # Abbrev [6] 0x91:0x5 DW_TAG_pointer_type
.long 150 # DW_AT_type
.byte 7 # Abbrev [7] 0x96:0x4 DW_TAG_base_type
.byte 10 # DW_AT_name
.byte 6 # DW_AT_encoding
.byte 1 # DW_AT_byte_size
.byte 0 # End Of Children Mark
.Ldebug_info_end0:
.section .debug_str_offsets,"",@progbits
.long 48 # Length of String Offsets Set
.short 5
.short 0
.Lstr_offsets_base0:
.section .debug_str,"MS",@progbits,1
.Linfo_string0:
.asciz "clang version 15.0.0)" # string offset=0
.Linfo_string1:
.asciz "main.cpp" # string offset=134
.Linfo_string2:
.asciz "/testLocList" # string offset=143
.Linfo_string3:
.asciz "_Z3usePi" # string offset=192
.Linfo_string4:
.asciz "use" # string offset=201
.Linfo_string5:
.asciz "x" # string offset=205
.Linfo_string6:
.asciz "int" # string offset=207
.Linfo_string7:
.asciz "main" # string offset=211
.Linfo_string8:
.asciz "argc" # string offset=216
.Linfo_string9:
.asciz "argv" # string offset=221
.Linfo_string10:
.asciz "char" # string offset=226
.section .debug_str_offsets,"",@progbits
.long .Linfo_string0
.long .Linfo_string1
.long .Linfo_string2
.long .Linfo_string3
.long .Linfo_string4
.long .Linfo_string5
.long .Linfo_string6
.long .Linfo_string7
.long .Linfo_string8
.long .Linfo_string9
.long .Linfo_string10
.section .debug_addr,"",@progbits
.long .Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution
.Ldebug_addr_start0:
.short 5 # DWARF version number
.byte 8 # Address size
.byte 0 # Segment selector size
.Laddr_table_base0:
.quad .Lfunc_begin0
.quad .Lfunc_begin1
.Ldebug_addr_end0:
.ident "clang version 15.0.0"
.section ".note.GNU-stack","",@progbits
.addrsig
.section .debug_line,"",@progbits
.Lline_table_start0:

View File

@ -0,0 +1,302 @@
# REQUIRES: system-linux
# RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %s -o %tmain.o
# RUN: %clang %cflags -dwarf-5 %tmain.o -o %t.exe -Wl,-q
# RUN: llvm-bolt %t.exe -o %t.bolt -update-debug-sections
# RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.exe | FileCheck --check-prefix=PRECHECK %s
# RUN: llvm-dwarfdump --show-form --verbose --debug-addr %t.bolt > %t.txt
# RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt >> %t.txt
# This test checks that we correctly handle DW_AT_low_pc [DW_FORM_addrx] that is part of DW_TAG_label.
# PRECHECK: version = 0x0005
# PRECHECK: DW_TAG_label
# PRECHECK-NEXT: DW_AT_name
# PRECHECK-NEXT: DW_AT_decl_file
# PRECHECK-NEXT: DW_AT_decl_line
# PRECHECK-NEXT:DW_AT_low_pc [DW_FORM_addrx] (indexed (00000001)
# PRECHECK: DW_TAG_label
# PRECHECK-NEXT: DW_AT_name
# PRECHECK-NEXT: DW_AT_decl_file
# PRECHECK-NEXT: DW_AT_decl_line
# PRECHECK-NEXT:DW_AT_low_pc [DW_FORM_addrx] (indexed (00000002)
# POSTCHECK: Addrs: [
# POSTCHECK-NEXT: 0x
# POSTCHECK-NEXT: 0x
# POSTCHECK-NEXT: 0x[[#%.16x,ADDR:]]
# POSTCHECK-NEXT: 0x[[#%.16x,ADDR2:]]
# POSTCHECK: version = 0x0005
# POSTCHECK: DW_TAG_label
# POSTCHECK-NEXT: DW_AT_name
# POSTCHECK-NEXT: DW_AT_decl_file
# POSTCHECK-NEXT: DW_AT_decl_line
# POSTCHECK-NEXT:
# POSTCHECK-NEXT:DW_AT_low_pc [DW_FORM_addrx] (indexed (00000002)
# POSTCHECK-SAME: [0x[[#ADDR]]
# POSTCHECK: DW_TAG_label
# POSTCHECK-NEXT: DW_AT_name
# POSTCHECK-NEXT: DW_AT_decl_file
# POSTCHECK-NEXT: DW_AT_decl_line
# POSTCHECK-NEXT:
# POSTCHECK-NEXT:DW_AT_low_pc [DW_FORM_addrx] (indexed (00000003)
# POSTCHECK-SAME: [0x[[#ADDR2]]
# clang++ main.cpp -g -S
# int main() {
# int a = 4;
# if (a == 5)
# goto LABEL1;
# else
# goto LABEL2;
# LABEL1:a++;
# LABEL2:a--;
# return 0;
# }
.text
.file "main.cpp"
.globl main # -- Begin function main
.p2align 4, 0x90
.type main,@function
main: # @main
.Lfunc_begin0:
.file 0 "/testLabel" "main.cpp" md5 0xa0bd66020d06f1303de7008e3c542050
.loc 0 1 0 # main.cpp:1:0
.cfi_startproc
# %bb.0: # %entry
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
movl $0, -4(%rbp)
.Ltmp0:
.loc 0 2 7 prologue_end # main.cpp:2:7
movl $4, -8(%rbp)
.Ltmp1:
.loc 0 3 9 # main.cpp:3:9
cmpl $5, -8(%rbp)
.Ltmp2:
.loc 0 3 7 is_stmt 0 # main.cpp:3:7
jne .LBB0_2
# %bb.1: # %if.then
.Ltmp3:
.loc 0 4 5 is_stmt 1 # main.cpp:4:5
jmp .LBB0_3
.LBB0_2: # %if.else
.loc 0 6 5 # main.cpp:6:5
jmp .LBB0_4
.Ltmp4:
.LBB0_3: # %LABEL1
#DEBUG_LABEL: main:LABEL1
.loc 0 7 11 # main.cpp:7:11
movl -8(%rbp), %eax
addl $1, %eax
movl %eax, -8(%rbp)
.LBB0_4: # %LABEL2
.Ltmp5:
#DEBUG_LABEL: main:LABEL2
.loc 0 8 11 # main.cpp:8:11
movl -8(%rbp), %eax
addl $-1, %eax
movl %eax, -8(%rbp)
.loc 0 9 3 # main.cpp:9:3
xorl %eax, %eax
popq %rbp
.cfi_def_cfa %rsp, 8
retq
.Ltmp6:
.Lfunc_end0:
.size main, .Lfunc_end0-main
.cfi_endproc
# -- End function
.section .debug_abbrev,"",@progbits
.byte 1 # Abbreviation Code
.byte 17 # DW_TAG_compile_unit
.byte 1 # DW_CHILDREN_yes
.byte 37 # DW_AT_producer
.byte 37 # DW_FORM_strx1
.byte 19 # DW_AT_language
.byte 5 # DW_FORM_data2
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 114 # DW_AT_str_offsets_base
.byte 23 # DW_FORM_sec_offset
.byte 16 # DW_AT_stmt_list
.byte 23 # DW_FORM_sec_offset
.byte 27 # DW_AT_comp_dir
.byte 37 # DW_FORM_strx1
.byte 17 # DW_AT_low_pc
.byte 27 # DW_FORM_addrx
.byte 18 # DW_AT_high_pc
.byte 6 # DW_FORM_data4
.byte 115 # DW_AT_addr_base
.byte 23 # DW_FORM_sec_offset
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 2 # Abbreviation Code
.byte 46 # DW_TAG_subprogram
.byte 1 # DW_CHILDREN_yes
.byte 17 # DW_AT_low_pc
.byte 27 # DW_FORM_addrx
.byte 18 # DW_AT_high_pc
.byte 6 # DW_FORM_data4
.byte 64 # DW_AT_frame_base
.byte 24 # DW_FORM_exprloc
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 58 # DW_AT_decl_file
.byte 11 # DW_FORM_data1
.byte 59 # DW_AT_decl_line
.byte 11 # DW_FORM_data1
.byte 73 # DW_AT_type
.byte 19 # DW_FORM_ref4
.byte 63 # DW_AT_external
.byte 25 # DW_FORM_flag_present
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 3 # Abbreviation Code
.byte 52 # DW_TAG_variable
.byte 0 # DW_CHILDREN_no
.byte 2 # DW_AT_location
.byte 24 # DW_FORM_exprloc
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 58 # DW_AT_decl_file
.byte 11 # DW_FORM_data1
.byte 59 # DW_AT_decl_line
.byte 11 # DW_FORM_data1
.byte 73 # DW_AT_type
.byte 19 # DW_FORM_ref4
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 4 # Abbreviation Code
.byte 10 # DW_TAG_label
.byte 0 # DW_CHILDREN_no
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 58 # DW_AT_decl_file
.byte 11 # DW_FORM_data1
.byte 59 # DW_AT_decl_line
.byte 11 # DW_FORM_data1
.byte 17 # DW_AT_low_pc
.byte 27 # DW_FORM_addrx
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 5 # Abbreviation Code
.byte 36 # DW_TAG_base_type
.byte 0 # DW_CHILDREN_no
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 62 # DW_AT_encoding
.byte 11 # DW_FORM_data1
.byte 11 # DW_AT_byte_size
.byte 11 # DW_FORM_data1
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 0 # EOM(3)
.section .debug_info,"",@progbits
.Lcu_begin0:
.long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
.Ldebug_info_start0:
.short 5 # DWARF version number
.byte 1 # DWARF Unit Type
.byte 8 # Address Size (in bytes)
.long .debug_abbrev # Offset Into Abbrev. Section
.byte 1 # Abbrev [1] 0xc:0x41 DW_TAG_compile_unit
.byte 0 # DW_AT_producer
.short 33 # DW_AT_language
.byte 1 # DW_AT_name
.long .Lstr_offsets_base0 # DW_AT_str_offsets_base
.long .Lline_table_start0 # DW_AT_stmt_list
.byte 2 # DW_AT_comp_dir
.byte 0 # DW_AT_low_pc
.long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
.long .Laddr_table_base0 # DW_AT_addr_base
.byte 2 # Abbrev [2] 0x23:0x25 DW_TAG_subprogram
.byte 0 # DW_AT_low_pc
.long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
.byte 1 # DW_AT_frame_base
.byte 86
.byte 3 # DW_AT_name
.byte 0 # DW_AT_decl_file
.byte 1 # DW_AT_decl_line
.long 72 # DW_AT_type
# DW_AT_external
.byte 3 # Abbrev [3] 0x32:0xb DW_TAG_variable
.byte 2 # DW_AT_location
.byte 145
.byte 120
.byte 5 # DW_AT_name
.byte 0 # DW_AT_decl_file
.byte 2 # DW_AT_decl_line
.long 72 # DW_AT_type
.byte 4 # Abbrev [4] 0x3d:0x5 DW_TAG_label
.byte 6 # DW_AT_name
.byte 0 # DW_AT_decl_file
.byte 7 # DW_AT_decl_line
.byte 1 # DW_AT_low_pc
.byte 4 # Abbrev [4] 0x42:0x5 DW_TAG_label
.byte 7 # DW_AT_name
.byte 0 # DW_AT_decl_file
.byte 8 # DW_AT_decl_line
.byte 2 # DW_AT_low_pc
.byte 0 # End Of Children Mark
.byte 5 # Abbrev [5] 0x48:0x4 DW_TAG_base_type
.byte 4 # DW_AT_name
.byte 5 # DW_AT_encoding
.byte 4 # DW_AT_byte_size
.byte 0 # End Of Children Mark
.Ldebug_info_end0:
.section .debug_str_offsets,"",@progbits
.long 36 # Length of String Offsets Set
.short 5
.short 0
.Lstr_offsets_base0:
.section .debug_str,"MS",@progbits,1
.Linfo_string0:
.asciz "clang version 15.0.0" # string offset=0
.Linfo_string1:
.asciz "main.cpp" # string offset=134
.Linfo_string2:
.asciz "/testLabel" # string offset=143
.Linfo_string3:
.asciz "main" # string offset=190
.Linfo_string4:
.asciz "int" # string offset=195
.Linfo_string5:
.asciz "a" # string offset=199
.Linfo_string6:
.asciz "LABEL1" # string offset=201
.Linfo_string7:
.asciz "LABEL2" # string offset=208
.section .debug_str_offsets,"",@progbits
.long .Linfo_string0
.long .Linfo_string1
.long .Linfo_string2
.long .Linfo_string3
.long .Linfo_string4
.long .Linfo_string5
.long .Linfo_string6
.long .Linfo_string7
.section .debug_addr,"",@progbits
.long .Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution
.Ldebug_addr_start0:
.short 5 # DWARF version number
.byte 8 # Address size
.byte 0 # Segment selector size
.Laddr_table_base0:
.quad .Lfunc_begin0
.quad .Ltmp4
.quad .Ltmp5
.Ldebug_addr_end0:
.ident "clang version 15.0.0"
.section ".note.GNU-stack","",@progbits
.addrsig
.section .debug_line,"",@progbits
.Lline_table_start0:

View File

@ -0,0 +1,461 @@
# REQUIRES: system-linux
# RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %s -o %tmain.o
# RUN: %clang %cflags -dwarf-5 %tmain.o -o %t.exe -Wl,-q
# RUN: llvm-bolt %t.exe -o %t.bolt -update-debug-sections
# RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.exe | FileCheck --check-prefix=PRECHECK %s
# RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt | FileCheck --check-prefix=POSTCHECK %s
# This test checks that we correctly encode new index into .debug_addr section
# from DW_AT_location [DW_FORM_exprloc] (DW_OP_addrx 0x#)
# PRECHECK: version = 0x0005
# PRECHECK: DW_TAG_variable
# PRECHECK: DW_AT_location [DW_FORM_exprloc] (DW_OP_addrx 0x0)
# PRECHECK: DW_TAG_variable
# PRECHECK: DW_AT_location [DW_FORM_exprloc] (DW_OP_addrx 0x1)
# PRECHECK-EMPTY:
# POSTCHECK: version = 0x0005
# POSTCHECK: DW_TAG_variable
# POSTCHECK: DW_AT_location [DW_FORM_exprloc] (DW_OP_addrx 0x3)
# POSTCHECK-EMPTY:
# POSTCHECK: DW_TAG_variable
# POSTCHECK: DW_AT_location [DW_FORM_exprloc] (DW_OP_addrx 0x4)
# POSTCHECK-EMPTY:
# clang++ main.cpp -g -O2
# void use(int * x, int * y) {
# *x += 4;
# *y -= 2;
# }
#
# int x = 0;
# int y = 1;
# int main(int argc, char *argv[]) {
# x = argc;
# y = argc + 3;
# use(&x, &y);
# return x + y;
# }
.text
.file "main.cpp"
.file 0 "/testLocExprLoc" "main.cpp" md5 0xd4fd79ce0087c4cefd089752bf2182c6
.globl _Z3usePiS_ # -- Begin function _Z3usePiS_
.p2align 4, 0x90
.type _Z3usePiS_,@function
_Z3usePiS_: # @_Z3usePiS_
.Lfunc_begin0:
.loc 0 1 0 # main.cpp:1:0
.cfi_startproc
# %bb.0: # %entry
#DEBUG_VALUE: use:x <- $rdi
#DEBUG_VALUE: use:y <- $rsi
.loc 0 2 4 prologue_end # main.cpp:2:4
addl $4, (%rdi)
.loc 0 3 4 # main.cpp:3:4
addl $-2, (%rsi)
.loc 0 4 1 # main.cpp:4:1
retq
.Ltmp0:
.Lfunc_end0:
.size _Z3usePiS_, .Lfunc_end0-_Z3usePiS_
.cfi_endproc
# -- End function
.globl main # -- Begin function main
.p2align 4, 0x90
.type main,@function
main: # @main
.Lfunc_begin1:
.loc 0 8 0 # main.cpp:8:0
.cfi_startproc
# %bb.0: # %entry
#DEBUG_VALUE: main:argc <- $edi
#DEBUG_VALUE: main:argv <- $rsi
# kill: def $edi killed $edi def $rdi
.loc 0 2 4 prologue_end # main.cpp:2:4
leal 4(%rdi), %eax
movl %eax, x(%rip)
.Ltmp1:
#DEBUG_VALUE: use:x <- undef
.loc 0 3 4 # main.cpp:3:4
leal 1(%rdi), %eax
movl %eax, y(%rip)
.Ltmp2:
#DEBUG_VALUE: use:y <- undef
.loc 0 12 13 # main.cpp:12:13
leal (%rdi,%rdi), %eax
addl $5, %eax
.loc 0 12 4 is_stmt 0 # main.cpp:12:4
retq
.Ltmp3:
.Lfunc_end1:
.size main, .Lfunc_end1-main
.cfi_endproc
# -- End function
.type x,@object # @x
.bss
.globl x
.p2align 2
x:
.long 0 # 0x0
.size x, 4
.type y,@object # @y
.data
.globl y
.p2align 2
y:
.long 1 # 0x1
.size y, 4
.section .debug_abbrev,"",@progbits
.byte 1 # Abbreviation Code
.byte 17 # DW_TAG_compile_unit
.byte 1 # DW_CHILDREN_yes
.byte 37 # DW_AT_producer
.byte 37 # DW_FORM_strx1
.byte 19 # DW_AT_language
.byte 5 # DW_FORM_data2
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 114 # DW_AT_str_offsets_base
.byte 23 # DW_FORM_sec_offset
.byte 16 # DW_AT_stmt_list
.byte 23 # DW_FORM_sec_offset
.byte 27 # DW_AT_comp_dir
.byte 37 # DW_FORM_strx1
.byte 17 # DW_AT_low_pc
.byte 27 # DW_FORM_addrx
.byte 18 # DW_AT_high_pc
.byte 6 # DW_FORM_data4
.byte 115 # DW_AT_addr_base
.byte 23 # DW_FORM_sec_offset
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 2 # Abbreviation Code
.byte 52 # DW_TAG_variable
.byte 0 # DW_CHILDREN_no
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 73 # DW_AT_type
.byte 19 # DW_FORM_ref4
.byte 63 # DW_AT_external
.byte 25 # DW_FORM_flag_present
.byte 58 # DW_AT_decl_file
.byte 11 # DW_FORM_data1
.byte 59 # DW_AT_decl_line
.byte 11 # DW_FORM_data1
.byte 2 # DW_AT_location
.byte 24 # DW_FORM_exprloc
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 3 # Abbreviation Code
.byte 36 # DW_TAG_base_type
.byte 0 # DW_CHILDREN_no
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 62 # DW_AT_encoding
.byte 11 # DW_FORM_data1
.byte 11 # DW_AT_byte_size
.byte 11 # DW_FORM_data1
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 4 # Abbreviation Code
.byte 46 # DW_TAG_subprogram
.byte 1 # DW_CHILDREN_yes
.byte 17 # DW_AT_low_pc
.byte 27 # DW_FORM_addrx
.byte 18 # DW_AT_high_pc
.byte 6 # DW_FORM_data4
.byte 64 # DW_AT_frame_base
.byte 24 # DW_FORM_exprloc
.byte 122 # DW_AT_call_all_calls
.byte 25 # DW_FORM_flag_present
.byte 49 # DW_AT_abstract_origin
.byte 19 # DW_FORM_ref4
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 5 # Abbreviation Code
.byte 5 # DW_TAG_formal_parameter
.byte 0 # DW_CHILDREN_no
.byte 2 # DW_AT_location
.byte 24 # DW_FORM_exprloc
.byte 49 # DW_AT_abstract_origin
.byte 19 # DW_FORM_ref4
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 6 # Abbreviation Code
.byte 46 # DW_TAG_subprogram
.byte 1 # DW_CHILDREN_yes
.byte 110 # DW_AT_linkage_name
.byte 37 # DW_FORM_strx1
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 58 # DW_AT_decl_file
.byte 11 # DW_FORM_data1
.byte 59 # DW_AT_decl_line
.byte 11 # DW_FORM_data1
.byte 63 # DW_AT_external
.byte 25 # DW_FORM_flag_present
.byte 32 # DW_AT_inline
.byte 33 # DW_FORM_implicit_const
.byte 1
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 7 # Abbreviation Code
.byte 5 # DW_TAG_formal_parameter
.byte 0 # DW_CHILDREN_no
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 58 # DW_AT_decl_file
.byte 11 # DW_FORM_data1
.byte 59 # DW_AT_decl_line
.byte 11 # DW_FORM_data1
.byte 73 # DW_AT_type
.byte 19 # DW_FORM_ref4
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 8 # Abbreviation Code
.byte 15 # DW_TAG_pointer_type
.byte 0 # DW_CHILDREN_no
.byte 73 # DW_AT_type
.byte 19 # DW_FORM_ref4
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 9 # Abbreviation Code
.byte 46 # DW_TAG_subprogram
.byte 1 # DW_CHILDREN_yes
.byte 17 # DW_AT_low_pc
.byte 27 # DW_FORM_addrx
.byte 18 # DW_AT_high_pc
.byte 6 # DW_FORM_data4
.byte 64 # DW_AT_frame_base
.byte 24 # DW_FORM_exprloc
.byte 122 # DW_AT_call_all_calls
.byte 25 # DW_FORM_flag_present
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 58 # DW_AT_decl_file
.byte 11 # DW_FORM_data1
.byte 59 # DW_AT_decl_line
.byte 11 # DW_FORM_data1
.byte 73 # DW_AT_type
.byte 19 # DW_FORM_ref4
.byte 63 # DW_AT_external
.byte 25 # DW_FORM_flag_present
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 10 # Abbreviation Code
.byte 5 # DW_TAG_formal_parameter
.byte 0 # DW_CHILDREN_no
.byte 2 # DW_AT_location
.byte 24 # DW_FORM_exprloc
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 58 # DW_AT_decl_file
.byte 11 # DW_FORM_data1
.byte 59 # DW_AT_decl_line
.byte 11 # DW_FORM_data1
.byte 73 # DW_AT_type
.byte 19 # DW_FORM_ref4
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 11 # Abbreviation Code
.byte 29 # DW_TAG_inlined_subroutine
.byte 0 # DW_CHILDREN_no
.byte 49 # DW_AT_abstract_origin
.byte 19 # DW_FORM_ref4
.byte 17 # DW_AT_low_pc
.byte 27 # DW_FORM_addrx
.byte 18 # DW_AT_high_pc
.byte 6 # DW_FORM_data4
.byte 88 # DW_AT_call_file
.byte 11 # DW_FORM_data1
.byte 89 # DW_AT_call_line
.byte 11 # DW_FORM_data1
.byte 87 # DW_AT_call_column
.byte 11 # DW_FORM_data1
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 0 # EOM(3)
.section .debug_info,"",@progbits
.Lcu_begin0:
.long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
.Ldebug_info_start0:
.short 5 # DWARF version number
.byte 1 # DWARF Unit Type
.byte 8 # Address Size (in bytes)
.long .debug_abbrev # Offset Into Abbrev. Section
.byte 1 # Abbrev [1] 0xc:0xa7 DW_TAG_compile_unit
.byte 0 # DW_AT_producer
.short 33 # DW_AT_language
.byte 1 # DW_AT_name
.long .Lstr_offsets_base0 # DW_AT_str_offsets_base
.long .Lline_table_start0 # DW_AT_stmt_list
.byte 2 # DW_AT_comp_dir
.byte 2 # DW_AT_low_pc
.long .Lfunc_end1-.Lfunc_begin0 # DW_AT_high_pc
.long .Laddr_table_base0 # DW_AT_addr_base
.byte 2 # Abbrev [2] 0x23:0xb DW_TAG_variable
.byte 3 # DW_AT_name
.long 46 # DW_AT_type
# DW_AT_external
.byte 0 # DW_AT_decl_file
.byte 6 # DW_AT_decl_line
.byte 2 # DW_AT_location
.byte 161
.byte 0
.byte 3 # Abbrev [3] 0x2e:0x4 DW_TAG_base_type
.byte 4 # DW_AT_name
.byte 5 # DW_AT_encoding
.byte 4 # DW_AT_byte_size
.byte 2 # Abbrev [2] 0x32:0xb DW_TAG_variable
.byte 5 # DW_AT_name
.long 46 # DW_AT_type
# DW_AT_external
.byte 0 # DW_AT_decl_file
.byte 7 # DW_AT_decl_line
.byte 2 # DW_AT_location
.byte 161
.byte 1
.byte 4 # Abbrev [4] 0x3d:0x1b DW_TAG_subprogram
.byte 2 # DW_AT_low_pc
.long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
.byte 1 # DW_AT_frame_base
.byte 87
# DW_AT_call_all_calls
.long 88 # DW_AT_abstract_origin
.byte 5 # Abbrev [5] 0x49:0x7 DW_TAG_formal_parameter
.byte 1 # DW_AT_location
.byte 85
.long 93 # DW_AT_abstract_origin
.byte 5 # Abbrev [5] 0x50:0x7 DW_TAG_formal_parameter
.byte 1 # DW_AT_location
.byte 84
.long 101 # DW_AT_abstract_origin
.byte 0 # End Of Children Mark
.byte 6 # Abbrev [6] 0x58:0x16 DW_TAG_subprogram
.byte 6 # DW_AT_linkage_name
.byte 7 # DW_AT_name
.byte 0 # DW_AT_decl_file
.byte 1 # DW_AT_decl_line
# DW_AT_external
# DW_AT_inline
.byte 7 # Abbrev [7] 0x5d:0x8 DW_TAG_formal_parameter
.byte 3 # DW_AT_name
.byte 0 # DW_AT_decl_file
.byte 1 # DW_AT_decl_line
.long 110 # DW_AT_type
.byte 7 # Abbrev [7] 0x65:0x8 DW_TAG_formal_parameter
.byte 5 # DW_AT_name
.byte 0 # DW_AT_decl_file
.byte 1 # DW_AT_decl_line
.long 110 # DW_AT_type
.byte 0 # End Of Children Mark
.byte 8 # Abbrev [8] 0x6e:0x5 DW_TAG_pointer_type
.long 46 # DW_AT_type
.byte 9 # Abbrev [9] 0x73:0x31 DW_TAG_subprogram
.byte 3 # DW_AT_low_pc
.long .Lfunc_end1-.Lfunc_begin1 # DW_AT_high_pc
.byte 1 # DW_AT_frame_base
.byte 87
# DW_AT_call_all_calls
.byte 8 # DW_AT_name
.byte 0 # DW_AT_decl_file
.byte 8 # DW_AT_decl_line
.long 46 # DW_AT_type
# DW_AT_external
.byte 10 # Abbrev [10] 0x82:0xa DW_TAG_formal_parameter
.byte 1 # DW_AT_location
.byte 85
.byte 9 # DW_AT_name
.byte 0 # DW_AT_decl_file
.byte 8 # DW_AT_decl_line
.long 46 # DW_AT_type
.byte 10 # Abbrev [10] 0x8c:0xa DW_TAG_formal_parameter
.byte 1 # DW_AT_location
.byte 84
.byte 10 # DW_AT_name
.byte 0 # DW_AT_decl_file
.byte 8 # DW_AT_decl_line
.long 164 # DW_AT_type
.byte 11 # Abbrev [11] 0x96:0xd DW_TAG_inlined_subroutine
.long 88 # DW_AT_abstract_origin
.byte 3 # DW_AT_low_pc
.long .Ltmp2-.Lfunc_begin1 # DW_AT_high_pc
.byte 0 # DW_AT_call_file
.byte 11 # DW_AT_call_line
.byte 4 # DW_AT_call_column
.byte 0 # End Of Children Mark
.byte 8 # Abbrev [8] 0xa4:0x5 DW_TAG_pointer_type
.long 169 # DW_AT_type
.byte 8 # Abbrev [8] 0xa9:0x5 DW_TAG_pointer_type
.long 174 # DW_AT_type
.byte 3 # Abbrev [3] 0xae:0x4 DW_TAG_base_type
.byte 11 # DW_AT_name
.byte 6 # DW_AT_encoding
.byte 1 # DW_AT_byte_size
.byte 0 # End Of Children Mark
.Ldebug_info_end0:
.section .debug_str_offsets,"",@progbits
.long 52 # Length of String Offsets Set
.short 5
.short 0
.Lstr_offsets_base0:
.section .debug_str,"MS",@progbits,1
.Linfo_string0:
.asciz "clang version 15.0.0" # string offset=0
.Linfo_string1:
.asciz "main.cpp" # string offset=134
.Linfo_string2:
.asciz "/testLocExprLoc" # string offset=143
.Linfo_string3:
.asciz "x" # string offset=195
.Linfo_string4:
.asciz "int" # string offset=197
.Linfo_string5:
.asciz "y" # string offset=201
.Linfo_string6:
.asciz "_Z3usePiS_" # string offset=203
.Linfo_string7:
.asciz "use" # string offset=214
.Linfo_string8:
.asciz "main" # string offset=218
.Linfo_string9:
.asciz "argc" # string offset=223
.Linfo_string10:
.asciz "argv" # string offset=228
.Linfo_string11:
.asciz "char" # string offset=233
.section .debug_str_offsets,"",@progbits
.long .Linfo_string0
.long .Linfo_string1
.long .Linfo_string2
.long .Linfo_string3
.long .Linfo_string4
.long .Linfo_string5
.long .Linfo_string6
.long .Linfo_string7
.long .Linfo_string8
.long .Linfo_string9
.long .Linfo_string10
.long .Linfo_string11
.section .debug_addr,"",@progbits
.long .Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution
.Ldebug_addr_start0:
.short 5 # DWARF version number
.byte 8 # Address size
.byte 0 # Segment selector size
.Laddr_table_base0:
.quad x
.quad y
.quad .Lfunc_begin0
.quad .Lfunc_begin1
.Ldebug_addr_end0:
.ident "clang version 15.0.0"
.section ".note.GNU-stack","",@progbits
.addrsig
.section .debug_line,"",@progbits
.Lline_table_start0:

View File

@ -0,0 +1,196 @@
# REQUIRES: system-linux
# RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %s -o %t1.o
# RUN: %clang %cflags -dwarf-5 %t1.o -o %t.exe -Wl,-q
# RUN: llvm-bolt %t.exe -o %t.bolt -update-debug-sections
# RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.exe | FileCheck --check-prefix=PRECHECK %s
# RUN: llvm-dwarfdump --show-form --verbose --debug-addr %t.bolt > %t.txt
# RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt >> %t.txt
# RUN: cat %t.txt | FileCheck --check-prefix=POSTCHECK %s
# This tests checks that DW_AT_low_pc/DW_AT_high_pc is converted to DW_AT_low_pc/DW_AT_ranges.
# Checks that DW_AT_rnglists_base is inserted, and that correct address is used.
# PRECHECK: version = 0x0005
# PRECHECK: DW_AT_low_pc
# PRECHECK-SAME: DW_FORM_addrx
# PRECHECK-SAME: (00000000)
# PRECHECK-NEXT: DW_AT_high_pc [DW_FORM_data4] (0x0000000f)
# PRECHECK-NEXT: DW_AT_addr_base [DW_FORM_sec_offset] (0x00000008)
# POSTCHECK: Addrs: [
# POSTCHECK-NEXT: 0x[[#%.16x,ADDR:]]
# POSTCHECK: version = 0x0005
# POSTCHECK: DW_AT_low_pc
# POSTCHECK-SAME: DW_FORM_addrx
# POSTCHECK-SAME: (00000001)
# POSTCHECK-SAME: address = 0x0000000000000000
# POSTCHECK-NEXT: DW_AT_ranges
# POSTCHECK-SAME: DW_FORM_rnglistx
# POSTCHECK-SAME: (0x0)
# POSTCHECK-SAME: rangelist = 0x00000014
# POSTCHECK-NEXT: [
# POSTCHECK-SAME: 0x[[#ADDR]]
# POSTCHECK-SAME: 0x[[#ADDR + 15]]
# POSTCHECK-NEXT: DW_AT_addr_base [DW_FORM_sec_offset] (0x00000008)
# POSTCHECK-NEXT: DW_AT_rnglists_base [DW_FORM_sec_offset] (0x0000000c)
# int main() {
# return 0;
# }
.text
.file "main.cpp"
.globl main # -- Begin function main
.p2align 4, 0x90
.type main,@function
main: # @main
.Lfunc_begin0:
.file 0 "." "main.cpp" md5 0xbb12fec8d002b1f0e06f7dee4604c6cc
.loc 0 1 0 # main.cpp:1:0
.cfi_startproc
# %bb.0: # %entry
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
movl $0, -4(%rbp)
.Ltmp0:
.loc 0 2 3 prologue_end # main.cpp:2:3
xorl %eax, %eax
popq %rbp
.cfi_def_cfa %rsp, 8
retq
.Ltmp1:
.Lfunc_end0:
.size main, .Lfunc_end0-main
.cfi_endproc
# -- End function
.section .debug_abbrev,"",@progbits
.byte 1 # Abbreviation Code
.byte 17 # DW_TAG_compile_unit
.byte 1 # DW_CHILDREN_yes
.byte 37 # DW_AT_producer
.byte 37 # DW_FORM_strx1
.byte 19 # DW_AT_language
.byte 5 # DW_FORM_data2
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 114 # DW_AT_str_offsets_base
.byte 23 # DW_FORM_sec_offset
.byte 16 # DW_AT_stmt_list
.byte 23 # DW_FORM_sec_offset
.byte 27 # DW_AT_comp_dir
.byte 37 # DW_FORM_strx1
.byte 17 # DW_AT_low_pc
.byte 27 # DW_FORM_addrx
.byte 18 # DW_AT_high_pc
.byte 6 # DW_FORM_data4
.byte 115 # DW_AT_addr_base
.byte 23 # DW_FORM_sec_offset
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 2 # Abbreviation Code
.byte 46 # DW_TAG_subprogram
.byte 0 # DW_CHILDREN_no
.byte 17 # DW_AT_low_pc
.byte 27 # DW_FORM_addrx
.byte 18 # DW_AT_high_pc
.byte 6 # DW_FORM_data4
.byte 64 # DW_AT_frame_base
.byte 24 # DW_FORM_exprloc
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 58 # DW_AT_decl_file
.byte 11 # DW_FORM_data1
.byte 59 # DW_AT_decl_line
.byte 11 # DW_FORM_data1
.byte 73 # DW_AT_type
.byte 19 # DW_FORM_ref4
.byte 63 # DW_AT_external
.byte 25 # DW_FORM_flag_present
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 3 # Abbreviation Code
.byte 36 # DW_TAG_base_type
.byte 0 # DW_CHILDREN_no
.byte 3 # DW_AT_name
.byte 37 # DW_FORM_strx1
.byte 62 # DW_AT_encoding
.byte 11 # DW_FORM_data1
.byte 11 # DW_AT_byte_size
.byte 11 # DW_FORM_data1
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 0 # EOM(3)
.section .debug_info,"",@progbits
.Lcu_begin0:
.long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
.Ldebug_info_start0:
.short 5 # DWARF version number
.byte 1 # DWARF Unit Type
.byte 8 # Address Size (in bytes)
.long .debug_abbrev # Offset Into Abbrev. Section
.byte 1 # Abbrev [1] 0xc:0x2b DW_TAG_compile_unit
.byte 0 # DW_AT_producer
.short 33 # DW_AT_language
.byte 1 # DW_AT_name
.long .Lstr_offsets_base0 # DW_AT_str_offsets_base
.long .Lline_table_start0 # DW_AT_stmt_list
.byte 2 # DW_AT_comp_dir
.byte 0 # DW_AT_low_pc
.long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
.long .Laddr_table_base0 # DW_AT_addr_base
.byte 2 # Abbrev [2] 0x23:0xf DW_TAG_subprogram
.byte 0 # DW_AT_low_pc
.long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
.byte 1 # DW_AT_frame_base
.byte 86
.byte 3 # DW_AT_name
.byte 0 # DW_AT_decl_file
.byte 1 # DW_AT_decl_line
.long 50 # DW_AT_type
# DW_AT_external
.byte 3 # Abbrev [3] 0x32:0x4 DW_TAG_base_type
.byte 4 # DW_AT_name
.byte 5 # DW_AT_encoding
.byte 4 # DW_AT_byte_size
.byte 0 # End Of Children Mark
.Ldebug_info_end0:
.section .debug_str_offsets,"",@progbits
.long 24 # Length of String Offsets Set
.short 5
.short 0
.Lstr_offsets_base0:
.section .debug_str,"MS",@progbits,1
.Linfo_string0:
.asciz "clang version 15.0.0" # string offset=0
.Linfo_string1:
.asciz "main.cpp" # string offset=134
.Linfo_string2:
.asciz "." # string offset=143
.Linfo_string3:
.asciz "main" # string offset=180
.Linfo_string4:
.asciz "int" # string offset=185
.section .debug_str_offsets,"",@progbits
.long .Linfo_string0
.long .Linfo_string1
.long .Linfo_string2
.long .Linfo_string3
.long .Linfo_string4
.section .debug_addr,"",@progbits
.long .Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution
.Ldebug_addr_start0:
.short 5 # DWARF version number
.byte 8 # Address size
.byte 0 # Segment selector size
.Laddr_table_base0:
.quad .Lfunc_begin0
.Ldebug_addr_end0:
.ident "clang version 15.0.0"
.section ".note.GNU-stack","",@progbits
.addrsig
.section .debug_line,"",@progbits
.Lline_table_start0:

View File

@ -0,0 +1,256 @@
# REQUIRES: system-linux
# RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %s -o %t1.o
# RUN: %clang %cflags -dwarf-5 %t1.o -o %t.exe -Wl,-q
# RUN: llvm-bolt %t.exe -o %t.bolt -update-debug-sections
# RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.exe | FileCheck --check-prefix=PRECHECK %s
# RUN: llvm-dwarfdump --show-form --verbose --debug-addr %t.bolt > %t.txt
# RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt >> %t.txt
# RUN: cat %t.txt | FileCheck --check-prefix=POSTCHECK %s
# This tests conversion for DWARF5 ranges DW_AT_ranges [DW_FORM_sec_offset] to DW_AT_ranges [DW_FORM_rnglistx]
# PRECHECK: version = 0x0005
# PRECHECK: DW_AT_ranges [DW_FORM_sec_offset]
# POSTCHECK: Addrs: [
# POSTCHECK-NEXT: 0x[[#%.16x,ADDR:]]
# POSTCHECK-NEXT: 0x[[#%.16x,ADDR1:]]
# POSTCHECK: version = 0x0005
# POSTCHECK: DW_AT_ranges [DW_FORM_rnglistx]
# POSTCHECK-SAME: (indexed (0x0) rangelist = 0x00000018
# POSTCHECK-NEXT: [0x[[#ADDR]], 0x[[#ADDR + 11]]
# POSTCHECK-NEXT: [0x[[#ADDR1]], 0x[[#ADDR1 + 11]]
# int foo() {
# return 3;
# }
#
# int main() {
# return foo();
# }
.file "main.cpp"
.text
.Ltext0:
.file 0 "/testRangeOffsetToRangeX" "main.cpp"
.section .text._Z3foov,"ax",@progbits
.globl _Z3foov
.type _Z3foov, @function
_Z3foov:
.LFB0:
.file 1 "main.cpp"
.loc 0 1 11
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
.loc 0 2 10
movl $3, %eax
.loc 0 3 1
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size _Z3foov, .-_Z3foov
.section .text.main,"ax",@progbits
.globl main
.type main, @function
main:
.LFB1:
.loc 0 5 12
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
.loc 0 6 13
call _Z3foov
.loc 0 6 14
nop
.loc 0 7 1
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE1:
.size main, .-main
.text
.Letext0:
.section .debug_info,"",@progbits
.Ldebug_info0:
.long 0x6e
.value 0x5
.byte 0x1
.byte 0x8
.long .Ldebug_abbrev0
.uleb128 0x1
.long .LASF2
.byte 0x21
.long .LASF0
.long .LASF1
.long .LLRL0
.quad 0
.long .Ldebug_line0
.uleb128 0x2
.long .LASF3
.byte 0x1
.byte 0x5
.byte 0x5
.long 0x48
.quad .LFB1
.quad .LFE1-.LFB1
.uleb128 0x1
.byte 0x9c
.uleb128 0x3
.byte 0x4
.byte 0x5
.string "int"
.uleb128 0x4
.string "foo"
.byte 0x1
.byte 0x1
.byte 0x5
.long .LASF4
.long 0x48
.quad .LFB0
.quad .LFE0-.LFB0
.uleb128 0x1
.byte 0x9c
.byte 0
.section .debug_abbrev,"",@progbits
.Ldebug_abbrev0:
.uleb128 0x1
.uleb128 0x11
.byte 0x1
.uleb128 0x25
.uleb128 0xe
.uleb128 0x13
.uleb128 0xb
.uleb128 0x3
.uleb128 0x1f
.uleb128 0x1b
.uleb128 0x1f
.uleb128 0x55
.uleb128 0x17
.uleb128 0x11
.uleb128 0x1
.uleb128 0x10
.uleb128 0x17
.byte 0
.byte 0
.uleb128 0x2
.uleb128 0x2e
.byte 0
.uleb128 0x3f
.uleb128 0x19
.uleb128 0x3
.uleb128 0xe
.uleb128 0x3a
.uleb128 0xb
.uleb128 0x3b
.uleb128 0xb
.uleb128 0x39
.uleb128 0xb
.uleb128 0x49
.uleb128 0x13
.uleb128 0x11
.uleb128 0x1
.uleb128 0x12
.uleb128 0x7
.uleb128 0x40
.uleb128 0x18
.uleb128 0x7c
.uleb128 0x19
.byte 0
.byte 0
.uleb128 0x3
.uleb128 0x24
.byte 0
.uleb128 0xb
.uleb128 0xb
.uleb128 0x3e
.uleb128 0xb
.uleb128 0x3
.uleb128 0x8
.byte 0
.byte 0
.uleb128 0x4
.uleb128 0x2e
.byte 0
.uleb128 0x3f
.uleb128 0x19
.uleb128 0x3
.uleb128 0x8
.uleb128 0x3a
.uleb128 0xb
.uleb128 0x3b
.uleb128 0xb
.uleb128 0x39
.uleb128 0xb
.uleb128 0x6e
.uleb128 0xe
.uleb128 0x49
.uleb128 0x13
.uleb128 0x11
.uleb128 0x1
.uleb128 0x12
.uleb128 0x7
.uleb128 0x40
.uleb128 0x18
.uleb128 0x7a
.uleb128 0x19
.byte 0
.byte 0
.byte 0
.section .debug_aranges,"",@progbits
.long 0x3c
.value 0x2
.long .Ldebug_info0
.byte 0x8
.byte 0
.value 0
.value 0
.quad .LFB0
.quad .LFE0-.LFB0
.quad .LFB1
.quad .LFE1-.LFB1
.quad 0
.quad 0
.section .debug_rnglists,"",@progbits
.Ldebug_ranges0:
.long .Ldebug_ranges3-.Ldebug_ranges2
.Ldebug_ranges2:
.value 0x5
.byte 0x8
.byte 0
.long 0
.LLRL0:
.byte 0x7
.quad .LFB0
.uleb128 .LFE0-.LFB0
.byte 0x7
.quad .LFB1
.uleb128 .LFE1-.LFB1
.byte 0
.Ldebug_ranges3:
.section .debug_line,"",@progbits
.Ldebug_line0:
.section .debug_str,"MS",@progbits,1
.LASF4:
.string "_Z3foov"
.LASF3:
.string "main"
.LASF2:
.string "GNU C++17 11.x"
.section .debug_line_str,"MS",@progbits,1
.LASF0:
.string "main.cpp"
.LASF1:
.string "/testRangeOffsetToRangeX"
.ident "GCC: (GNU) 11.x"
.section .note.GNU-stack,"",@progbits

View File

@ -0,0 +1,78 @@
# REQUIRES: system-linux
# RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf5_main.s -o %tmain.o
# RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf5_helper.s -o %thelper.o
# RUN: %clang %cflags -dwarf-5 %tmain.o %thelper.o -o %t.exe -Wl,-q
# RUN: llvm-bolt %t.exe -o %t.bolt -update-debug-sections
# RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.exe | FileCheck --check-prefix=PRECHECK %s
# RUN: llvm-dwarfdump --show-form --verbose --debug-addr %t.bolt > %t.txt
# RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt >> %t.txt
# RUN: cat %t.txt | FileCheck --check-prefix=POSTCHECK %s
# This tests checks that re-writing of .debug_loclists is handled correctly for two CUs,
# and two loclist entries.
# PRECHECK: version = 0x0005
# PRECHECK: DW_AT_loclists_base [DW_FORM_sec_offset] (0x0000000c)
# PRECHECK-EMPTY:
# PRECHECK: DW_TAG_variable
# PRECHECK: DW_AT_location [DW_FORM_loclistx]
# PRECHECK-SAME: indexed (0x0)
# PRECHECK-SAME: loclist = 0x00000014
# PRECHECK: DW_AT_location [DW_FORM_loclistx]
# PRECHECK-SAME: indexed (0x1)
# PRECHECK-SAME: loclist = 0x00000028
# PRECHECK: DW_AT_loclists_base [DW_FORM_sec_offset] (0x00000043)
# PRECHECK-EMPTY:
# PRECHECK: DW_TAG_variable
# PRECHECK: DW_TAG_variable
# PRECHECK: DW_AT_location [DW_FORM_loclistx]
# PRECHECK-SAME: indexed (0x0)
# PRECHECK-SAME: loclist = 0x00000047
# POSTCHECK: Addrs: [
# POSTCHECK-NEXT: 0x
# POSTCHECK-NEXT: 0x[[#%.16x,ADDR:]]
# POSTCHECK-NEXT: 0x
# POSTCHECK-NEXT: 0x[[#%.16x,ADDR2:]]
# For second CU.
# POSTCHECK: Addrs: [
# POSTCHECK-NEXT: 0x
# POSTCHECK-NEXT: 0x[[#%.16x,ADDR3:]]
# POSTCHECK-NEXT: 0x
# POSTCHECK-NEXT: 0x
# POSTCHECK-NEXT: 0x[[#%.16x,ADDR4:]]
# POSTCHECK: version = 0x0005
# POSTCHECK: DW_AT_loclists_base [DW_FORM_sec_offset] (0x0000000c)
# POSTCHECK: DW_AT_rnglists_base [DW_FORM_sec_offset] (0x0000000c)
# POSTCHECK-EMPTY
# POSTCHECK: DW_TAG_variable
# POSTCHECK: DW_AT_location [DW_FORM_loclistx]
# POSTCHECK-SAME: indexed (0x0)
# POSTCHECK-SAME: loclist = 0x00000014
# POSTCHECK-NEXT: [0x[[#ADDR]]
# POSTCHECK-SAME: 0x[[#ADDR + 6]]
# POSTCHECK-NEXT: [0x[[#ADDR2]]
# POSTCHECK-SAME: 0x[[#ADDR2 + 6]]
# POSTCHECK: DW_TAG_variable
# POSTCHECK: DW_AT_location [DW_FORM_loclistx]
# POSTCHECK-SAME: indexed (0x1)
# POSTCHECK-SAME: loclist = 0x00000028
# POSTCHECK-NEXT: [0x[[#ADDR2]]
# POSTCHECK-SAME: 0x[[#ADDR2 + 2]]
# Checking second CU
# POSTCHECK: version = 0x0005
# POSTCHECK: DW_AT_loclists_base [DW_FORM_sec_offset] (0x00000043)
# POSTCHECK: DW_AT_rnglists_base [DW_FORM_sec_offset] (0x00000033)
# POSTCHECK-EMPTY:
# POSTCHECK: DW_TAG_variable
# POSTCHECK: DW_TAG_variable
# POSTCHECK: DW_AT_location [DW_FORM_loclistx]
# POSTCHECK-SAME: indexed (0x0)
# POSTCHECK-SAME: loclist = 0x00000047
# POSTCHECK-NEXT: [0x[[#ADDR3]]
# POSTCHECK-SAME: 0x[[#ADDR3 + 3]]
# POSTCHECK-NEXT: [0x[[#ADDR4]]
# POSTCHECK-SAME: 0x[[#ADDR4 + 1]]

View File

@ -0,0 +1,110 @@
# REQUIRES: system-linux
# RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf5_main.s -o %tmain.o
# RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf5_helper.s -o %thelper.o
# RUN: %clang %cflags -dwarf-5 %tmain.o %thelper.o -o %t.exe -Wl,-q
# RUN: llvm-bolt %t.exe -o %t.bolt -update-debug-sections
# RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.exe | FileCheck --check-prefix=PRECHECK %s
# RUN: llvm-dwarfdump --show-form --verbose --debug-addr %t.bolt > %t.txt
# RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt >> %t.txt
# RUN: cat %t.txt | FileCheck --check-prefix=POSTCHECK %s
# This tests checks that re-writing of .debug_rnglists is handled correctly for two CUs,
# and DW_AT_low_pc/DW_AT_high_pc conversion is handled correctly.
# PRECHECK: version = 0x0005
# PRECHECK: DW_AT_low_pc [DW_FORM_addrx]
# PRECHECK: DW_AT_high_pc [DW_FORM_data4]
# PRECHECK: DW_AT_loclists_base [DW_FORM_sec_offset] (0x0000000c)
# PRECHECK-EMPTY:
# PRECHECK: version = 0x0005
# PRECHECK: DW_AT_low_pc [DW_FORM_addrx]
# PRECHECK: DW_AT_high_pc [DW_FORM_data4]
# PRECHECK: DW_AT_loclists_base [DW_FORM_sec_offset] (0x00000043)
# PRECHECK: DW_TAG_inlined_subroutine
# PRECHECK-NEXT: DW_AT_abstract_origin
# PRECHECK-NEXT: DW_AT_low_pc [DW_FORM_addrx]
# PRECHECK-NEXT: DW_AT_high_pc [DW_FORM_data4] (0x00000003)
# POSTCHECK: Addrs: [
# POSTCHECK-NEXT: 0x[[#%.16x,ADDR:]]
# POSTCHECK-NEXT: 0x[[#%.16x,ADDR1:]]
# POSTCHECK-NEXT: 0x
# POSTCHECK-NEXT: 0x[[#%.16x,ADDR2:]]
# For second CU.
# POSTCHECK: Addrs: [
# POSTCHECK-NEXT: 0x[[#%.16x,ADDR3:]]
# POSTCHECK-NEXT: 0x[[#%.16x,ADDR4:]]
# POSTCHECK: version = 0x0005
# POSTCHECK: DW_AT_ranges [DW_FORM_rnglistx]
# POSTCHECK-SAME: (indexed (0x0)
# POSTCHECK-SAME: rangelist = 0x00000018
# POSTCHECK-NEXT: [
# POSTCHECK-SAME: 0x[[#ADDR]]
# POSTCHECK-SAME: 0x[[#ADDR + 7]]
# POSTCHECK-NEXT: [
# POSTCHECK-SAME: 0x[[#ADDR1]]
# POSTCHECK-SAME: 0x[[#ADDR1 + 12]]
# POSTCHECK-NEXT: DW_AT_addr_base [DW_FORM_sec_offset] (0x00000008)
# POSTCHECK-NEXT: DW_AT_loclists_base [DW_FORM_sec_offset] (0x0000000c)
# POSTCHECK-NEXT: DW_AT_rnglists_base [DW_FORM_sec_offset] (0x0000000c)
# POSTCHECK-EMPTY
# POSTCHECK: DW_TAG_subprogram
# POSTCHECK-NEXT: DW_AT_low_pc [DW_FORM_addrx]
# POSTCHECK-SAME: indexed (00000002)
# POSTCHECK-SAME: address = 0x0000000000000000
# POSTCHECK-NEXT: DW_AT_ranges [DW_FORM_rnglistx]
# POSTCHECK-SAME: indexed (0x1)
# POSTCHECK-SAME: rangelist = 0x0000001f
# POSTCHECK-NEXT: [0x[[#ADDR]], 0x[[#ADDR + 7]])
# POSTCHECK: DW_TAG_subprogram
# POSTCHECK-NEXT: DW_AT_low_pc [DW_FORM_addrx]
# POSTCHECK-SAME: indexed (00000002)
# POSTCHECK-SAME: address = 0x0000000000000000
# POSTCHECK-NEXT: DW_AT_ranges [DW_FORM_rnglistx]
# POSTCHECK-SAME: indexed (0x2)
# POSTCHECK-SAME: rangelist = 0x00000023
# POSTCHECK-NEXT: [0x[[#ADDR1]], 0x[[#ADDR1 + 12]])
# Checking second CU
# POSTCHECK: version = 0x0005
# POSTCHECK: DW_AT_ranges [DW_FORM_rnglistx]
# POSTCHECK-SAME: (indexed (0x0)
# POSTCHECK-SAME: rangelist = 0x00000043
# POSTCHECK-NEXT: [0x[[#ADDR3]], 0x[[#ADDR3 + 4]])
# POSTCHECK-NEXT: [0x[[#ADDR4]], 0x[[#ADDR4 + 4]])
# POSTCHECK-NEXT: DW_AT_addr_base [DW_FORM_sec_offset] (0x00000030)
# POSTCHECK-NEXT: DW_AT_loclists_base [DW_FORM_sec_offset] (0x00000043)
# POSTCHECK-NEXT: DW_AT_rnglists_base [DW_FORM_sec_offset] (0x00000033)
# POSTCHECK-EMPTY
# POSTCHECK: DW_TAG_subprogram
# POSTCHECK-NEXT: DW_AT_low_pc [DW_FORM_addrx]
# POSTCHECK-SAME: indexed (00000002)
# POSTCHECK-SAME: address = 0x0000000000000000
# POSTCHECK-NEXT: DW_AT_ranges [DW_FORM_rnglistx]
# POSTCHECK-SAME: indexed (0x1)
# POSTCHECK-SAME: rangelist = 0x0000004a
# POSTCHECK-NEXT: [0x[[#ADDR3]], 0x[[#ADDR3 + 4]])
# POSTCHECK: DW_TAG_subprogram
# POSTCHECK: DW_TAG_subprogram
# POSTCHECK-NEXT: DW_AT_low_pc [DW_FORM_addrx]
# POSTCHECK-SAME: indexed (00000002)
# POSTCHECK-SAME: address = 0x0000000000000000
# POSTCHECK-NEXT: DW_AT_ranges [DW_FORM_rnglistx]
# POSTCHECK-SAME: indexed (0x2)
# POSTCHECK-SAME: rangelist = 0x0000004e
# POSTCHECK-NEXT: [0x[[#ADDR4]], 0x[[#ADDR4 + 4]])
# POSTCHECK: DW_TAG_inlined_subroutine
# POSTCHECK-NEXT: DW_AT_abstract_origin
# POSTCHECK-NEXT: DW_AT_low_pc [DW_FORM_addrx]
# POSTCHECK-SAME: indexed (00000002)
# POSTCHECK-SAME: address = 0x0000000000000000
# POSTCHECK-NEXT: DW_AT_ranges [DW_FORM_rnglistx]
# POSTCHECK-SAME: indexed (0x3)
# POSTCHECK-SAME: rangelist = 0x00000052
# POSTCHECK-NEXT: [0x[[#ADDR4]], 0x[[#ADDR4 + 3]])

View File

@ -0,0 +1,158 @@
# REQUIRES: system-linux
# RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %s -o %t1.o
# RUN: %clang %cflags -dwarf-5 %t1.o -o %t.exe -Wl,-q
# RUN: llvm-bolt %t.exe -o %t.bolt -update-debug-sections
# RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.exe | FileCheck --check-prefix=PRECHECK %s
# RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt | FileCheck --check-prefix=POSTCHECK %s
# This test checks we correctly insert DW_AT_addr_base, when converting DW_AT_low_pc into DW_AT_ranges.
# PRECHECK-NOT: DW_AT_addr_base
# POSTCHECK: DW_AT_ranges [DW_FORM_rnglistx]
# POSTCHECK: DW_AT_rnglists_base [DW_FORM_sec_offset] (0x0000000c)
# POSTCHECK-NEXT: DW_AT_addr_base [DW_FORM_sec_offset] (0x00000008)
# int main() {
# return 0;
# }
.file "main.cpp"
.text
.Ltext0:
.globl main
.type main, @function
main:
.LFB0:
.file 1 "main.cpp"
.loc 1 1 12
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
.loc 1 2 10
movl $0, %eax
.loc 1 3 1
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.Letext0:
.section .debug_info,"",@progbits
.Ldebug_info0:
.long 0x50
.value 0x5
.byte 0x1
.byte 0x8
.long .Ldebug_abbrev0
.uleb128 0x1
.long .LASF0
.byte 0x21
.long .LASF1
.long .LASF2
.quad .Ltext0
.quad .Letext0-.Ltext0
.long .Ldebug_line0
.uleb128 0x2
.long .LASF3
.byte 0x1
.byte 0x1
.byte 0x5
.long 0x4c
.quad .LFB0
.quad .LFE0-.LFB0
.uleb128 0x1
.byte 0x9c
.uleb128 0x3
.byte 0x4
.byte 0x5
.string "int"
.byte 0
.section .debug_abbrev,"",@progbits
.Ldebug_abbrev0:
.uleb128 0x1
.uleb128 0x11
.byte 0x1
.uleb128 0x25
.uleb128 0xe
.uleb128 0x13
.uleb128 0xb
.uleb128 0x3
.uleb128 0xe
.uleb128 0x1b
.uleb128 0xe
.uleb128 0x11
.uleb128 0x1
.uleb128 0x12
.uleb128 0x7
.uleb128 0x10
.uleb128 0x17
.byte 0
.byte 0
.uleb128 0x2
.uleb128 0x2e
.byte 0
.uleb128 0x3f
.uleb128 0x19
.uleb128 0x3
.uleb128 0xe
.uleb128 0x3a
.uleb128 0xb
.uleb128 0x3b
.uleb128 0xb
.uleb128 0x39
.uleb128 0xb
.uleb128 0x49
.uleb128 0x13
.uleb128 0x11
.uleb128 0x1
.uleb128 0x12
.uleb128 0x7
.uleb128 0x40
.uleb128 0x18
.uleb128 0x7a
.uleb128 0x19
.byte 0
.byte 0
.uleb128 0x3
.uleb128 0x24
.byte 0
.uleb128 0xb
.uleb128 0xb
.uleb128 0x3e
.uleb128 0xb
.uleb128 0x3
.uleb128 0x8
.byte 0
.byte 0
.byte 0
.section .debug_aranges,"",@progbits
.long 0x2c
.value 0x2
.long .Ldebug_info0
.byte 0x8
.byte 0
.value 0
.value 0
.quad .Ltext0
.quad .Letext0-.Ltext0
.quad 0
.quad 0
.section .debug_line,"",@progbits
.Ldebug_line0:
.section .debug_str,"MS",@progbits,1
.LASF0:
.string "GNU C++14 8.5.0 20210514 (Red Hat 8.5.0-3) -mtune=generic -march=x86-64 -g2 -gdwarf-5"
.LASF1:
.string "main.cpp"
.LASF3:
.string "main"
.LASF2:
.string "."
.ident "GCC: (GNU) 8.5.0 20210514 (Red Hat 8.5.0-3)"
.section .note.GNU-stack,"",@progbits

View File

@ -3,18 +3,18 @@
# DW_TAG_compile_unit->DW_AT_stmt_list where the DW_AT_decl_file is located (and
# not where the DW_AT_abstract_origin is located).
# DW_TAG_variable in CU 1 is using DW_AT_decl_file 3.
# CU 1 has files:
# CU 1 has files:
# file_names[ 1]: name: "inlinevarother.h"
# file_names[ 2]: name: "inlinevar1.c"
# file_names[ 3]: name: "inlinevar.h"
# CU 2 has files:
# CU 2 has files:
# file_names[ 1]: name: "inlinevar2.c"
# file_names[ 2]: name: "inlinevar.h"
# UNSUPPORTED: system-darwin, system-windows
# REQUIRES: target-x86_64
# RUN: %clang_host -o %t %s \
# RUN: %clang_host -gdwarf-4 -o %t %s \
# RUN: %S/Inputs/DW_TAG_variable-DW_AT_decl_file-DW_AT_abstract_origin-crosscu2.s
# RUN: %lldb %t \
@ -36,7 +36,7 @@ main: # @main
.Ltmp2:
.file 3 "" "./inlinevar.h"
.loc 3 2 16 prologue_end # ./inlinevar.h:2:16
movl $42, %eax
movl $42, %eax
pushq %rax
.loc 3 3 10 # ./inlinevar.h:3:10
.Ltmp3: