Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/llvm/llvm-project.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/bolt
diff options
context:
space:
mode:
authorAlexander Yermolovich <ayermolo@fb.com>2022-04-22 01:47:49 +0300
committerAlexander Yermolovich <ayermolo@fb.com>2022-04-22 02:02:23 +0300
commit014cd37f5141af24c3082c70a251f84f48992022 (patch)
tree248f708ef8d1ee5136852a27738636c2efb8e655 /bolt
parent334899110639297d62618f2bb5f8da9c0c46698a (diff)
[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
Diffstat (limited to 'bolt')
-rw-r--r--bolt/include/bolt/Core/BinaryContext.h14
-rw-r--r--bolt/include/bolt/Core/DebugData.h169
-rw-r--r--bolt/include/bolt/Rewrite/DWARFRewriter.h10
-rw-r--r--bolt/lib/Core/BinaryContext.cpp54
-rw-r--r--bolt/lib/Core/DebugData.cpp355
-rw-r--r--bolt/lib/Rewrite/DWARFRewriter.cpp439
-rw-r--r--bolt/lib/Rewrite/RewriteInstance.cpp5
-rw-r--r--bolt/test/X86/Inputs/dwarf5_helper.s424
-rw-r--r--bolt/test/X86/Inputs/dwarf5_main.s394
-rw-r--r--bolt/test/X86/dwarf5-debug-info-dwarf4-debug-line.s167
-rw-r--r--bolt/test/X86/dwarf5-debug-line.s185
-rw-r--r--bolt/test/X86/dwarf5-debug-loclists.s439
-rw-r--r--bolt/test/X86/dwarf5-label-low-pc.s302
-rw-r--r--bolt/test/X86/dwarf5-locexpr-addrx.s461
-rw-r--r--bolt/test/X86/dwarf5-lowpc-highpc-convert.s196
-rw-r--r--bolt/test/X86/dwarf5-rangeoffset-to-rangeindex.s256
-rw-r--r--bolt/test/X86/dwarf5-two-loclists.test78
-rw-r--r--bolt/test/X86/dwarf5-two-rnglists.test110
-rw-r--r--bolt/test/X86/insert-addr-rnglists_base.s158
19 files changed, 4062 insertions, 154 deletions
diff --git a/bolt/include/bolt/Core/BinaryContext.h b/bolt/include/bolt/Core/BinaryContext.h
index c1b6887a55c8..9e1db3a78d0a 100644
--- a/bolt/include/bolt/Core/BinaryContext.h
+++ b/bolt/include/bolt/Core/BinaryContext.h
@@ -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;
diff --git a/bolt/include/bolt/Core/DebugData.h b/bolt/include/bolt/Core/DebugData.h
index c3463782f7fc..3e60f0ad2dc2 100644
--- a/bolt/include/bolt/Core/DebugData.h
+++ b/bolt/include/bolt/Core/DebugData.h
@@ -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 {
diff --git a/bolt/include/bolt/Rewrite/DWARFRewriter.h b/bolt/include/bolt/Rewrite/DWARFRewriter.h
index 74e10b146c53..1869a7e6ff98 100644
--- a/bolt/include/bolt/Rewrite/DWARFRewriter.h
+++ b/bolt/include/bolt/Rewrite/DWARFRewriter.h
@@ -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);
diff --git a/bolt/lib/Core/BinaryContext.cpp b/bolt/lib/Core/BinaryContext.cpp
index 251d3831c019..92ddc2603066 100644
--- a/bolt/lib/Core/BinaryContext.cpp
+++ b/bolt/lib/Core/BinaryContext.cpp
@@ -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));
}
}
diff --git a/bolt/lib/Core/DebugData.cpp b/bolt/lib/Core/DebugData.cpp
index 2ebd2c03838d..dfb041bb55ae 100644
--- a/bolt/lib/Core/DebugData.cpp
+++ b/bolt/lib/Core/DebugData.cpp
@@ -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++);
+ }
+
+ 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 DebugAddrWriter::getOffset(uint64_t DWOId) {
- auto Iter = DWOIdToOffsetMap.find(DWOId);
+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
diff --git a/bolt/lib/Rewrite/DWARFRewriter.cpp b/bolt/lib/Rewrite/DWARFRewriter.cpp
index 12bfd5af6627..1b52bd586f58 100644
--- a/bolt/lib/Rewrite/DWARFRewriter.cpp
+++ b/bolt/lib/Rewrite/DWARFRewriter.cpp
@@ -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());
+
+ if (BC.isDWARF5Used()) {
+ std::unique_ptr<DebugBufferVector> LocationListSectionContents =
+ makeFinalLocListsSection(DebugInfoPatcher, DWARFVersion::DWARF5);
+ BC.registerOrUpdateNoteSection(".debug_loclists",
+ copyByteArray(*LocationListSectionContents),
+ LocationListSectionContents->size());
+ }
- std::unique_ptr<DebugBufferVector> LocationListSectionContents =
- makeFinalLocListsSection(DebugInfoPatcher);
- BC.registerOrUpdateNoteSection(".debug_loc",
- 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);
}
diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
index 735090ae3399..dd128161e233 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -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";
diff --git a/bolt/test/X86/Inputs/dwarf5_helper.s b/bolt/test/X86/Inputs/dwarf5_helper.s
new file mode 100644
index 000000000000..f3e5bc2ea8ea
--- /dev/null
+++ b/bolt/test/X86/Inputs/dwarf5_helper.s
@@ -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:
diff --git a/bolt/test/X86/Inputs/dwarf5_main.s b/bolt/test/X86/Inputs/dwarf5_main.s
new file mode 100644
index 000000000000..ec0c50cba569
--- /dev/null
+++ b/bolt/test/X86/Inputs/dwarf5_main.s
@@ -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:
diff --git a/bolt/test/X86/dwarf5-debug-info-dwarf4-debug-line.s b/bolt/test/X86/dwarf5-debug-info-dwarf4-debug-line.s
new file mode 100644
index 000000000000..4e7e7cd7b4b7
--- /dev/null
+++ b/bolt/test/X86/dwarf5-debug-info-dwarf4-debug-line.s
@@ -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
diff --git a/bolt/test/X86/dwarf5-debug-line.s b/bolt/test/X86/dwarf5-debug-line.s
new file mode 100644
index 000000000000..040a25987108
--- /dev/null
+++ b/bolt/test/X86/dwarf5-debug-line.s
@@ -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:
diff --git a/bolt/test/X86/dwarf5-debug-loclists.s b/bolt/test/X86/dwarf5-debug-loclists.s
new file mode 100644
index 000000000000..440e94115701
--- /dev/null
+++ b/bolt/test/X86/dwarf5-debug-loclists.s
@@ -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:
diff --git a/bolt/test/X86/dwarf5-label-low-pc.s b/bolt/test/X86/dwarf5-label-low-pc.s
new file mode 100644
index 000000000000..fbcbbe052437
--- /dev/null
+++ b/bolt/test/X86/dwarf5-label-low-pc.s
@@ -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:
diff --git a/bolt/test/X86/dwarf5-locexpr-addrx.s b/bolt/test/X86/dwarf5-locexpr-addrx.s
new file mode 100644
index 000000000000..0e1d1a5c978d
--- /dev/null
+++ b/bolt/test/X86/dwarf5-locexpr-addrx.s
@@ -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:
diff --git a/bolt/test/X86/dwarf5-lowpc-highpc-convert.s b/bolt/test/X86/dwarf5-lowpc-highpc-convert.s
new file mode 100644
index 000000000000..25778131aa47
--- /dev/null
+++ b/bolt/test/X86/dwarf5-lowpc-highpc-convert.s
@@ -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:
diff --git a/bolt/test/X86/dwarf5-rangeoffset-to-rangeindex.s b/bolt/test/X86/dwarf5-rangeoffset-to-rangeindex.s
new file mode 100644
index 000000000000..94f01fcc6edc
--- /dev/null
+++ b/bolt/test/X86/dwarf5-rangeoffset-to-rangeindex.s
@@ -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
diff --git a/bolt/test/X86/dwarf5-two-loclists.test b/bolt/test/X86/dwarf5-two-loclists.test
new file mode 100644
index 000000000000..54194b46ee5c
--- /dev/null
+++ b/bolt/test/X86/dwarf5-two-loclists.test
@@ -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]]
diff --git a/bolt/test/X86/dwarf5-two-rnglists.test b/bolt/test/X86/dwarf5-two-rnglists.test
new file mode 100644
index 000000000000..bbf3ab642b1f
--- /dev/null
+++ b/bolt/test/X86/dwarf5-two-rnglists.test
@@ -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]])
diff --git a/bolt/test/X86/insert-addr-rnglists_base.s b/bolt/test/X86/insert-addr-rnglists_base.s
new file mode 100644
index 000000000000..76ba7917a727
--- /dev/null
+++ b/bolt/test/X86/insert-addr-rnglists_base.s
@@ -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