[llvm] [SHT_LLVM_FUNC_ADDR_MAP] Introduce function address map section and emit dynamic instruction count (PR #123804)
Lei Wang via llvm-commits
llvm-commits at lists.llvm.org
Tue Jan 21 10:52:43 PST 2025
https://github.com/wlei-llvm created https://github.com/llvm/llvm-project/pull/123804
None
>From 29e8cd21f841408f04bd9c81bfc6be180290dc17 Mon Sep 17 00:00:00 2001
From: wlei <wlei at fb.com>
Date: Mon, 20 Jan 2025 21:55:36 -0800
Subject: [PATCH] [SHT_LLVM_FUNC_ADDR_MAP] Introduce function address map
section and emit dynamic instruction count feature
---
llvm/include/llvm/BinaryFormat/ELF.h | 1 +
llvm/include/llvm/CodeGen/AsmPrinter.h | 2 +
llvm/include/llvm/MC/MCContext.h | 5 +
llvm/include/llvm/MC/MCObjectFileInfo.h | 2 +
llvm/include/llvm/Object/ELF.h | 4 +
llvm/include/llvm/Object/ELFTypes.h | 38 +++++++
llvm/include/llvm/ObjectYAML/ELFYAML.h | 27 +++++
llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 57 +++++++++-
llvm/lib/MC/MCObjectFileInfo.cpp | 18 +++
llvm/lib/MC/MCParser/ELFAsmParser.cpp | 2 +
llvm/lib/MC/MCSectionELF.cpp | 2 +
llvm/lib/Object/ELF.cpp | 106 +++++++++++++++++-
llvm/lib/ObjectYAML/ELFEmitter.cpp | 23 ++++
llvm/lib/ObjectYAML/ELFYAML.cpp | 21 ++++
.../function-address-map-function-sections.ll | 41 +++++++
llvm/test/MC/AsmParser/llvm_section_types.s | 5 +
.../tools/llvm-readobj/ELF/func-addr-map.test | 96 ++++++++++++++++
llvm/tools/llvm-readobj/ELFDumper.cpp | 61 ++++++++++
llvm/tools/llvm-readobj/ObjDumper.h | 1 +
llvm/tools/llvm-readobj/Opts.td | 1 +
llvm/tools/llvm-readobj/llvm-readobj.cpp | 4 +
llvm/tools/obj2yaml/elf2yaml.cpp | 53 +++++++++
22 files changed, 568 insertions(+), 2 deletions(-)
create mode 100644 llvm/test/CodeGen/X86/function-address-map-function-sections.ll
create mode 100644 llvm/test/tools/llvm-readobj/ELF/func-addr-map.test
diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h
index 1bc69f791bd84c..3bcc1248bf8269 100644
--- a/llvm/include/llvm/BinaryFormat/ELF.h
+++ b/llvm/include/llvm/BinaryFormat/ELF.h
@@ -1139,6 +1139,7 @@ enum : unsigned {
SHT_LLVM_OFFLOADING = 0x6fff4c0b, // LLVM device offloading data.
SHT_LLVM_LTO = 0x6fff4c0c, // .llvm.lto for fat LTO.
SHT_LLVM_JT_SIZES = 0x6fff4c0d, // LLVM jump tables sizes.
+ SHT_LLVM_FUNC_ADDR_MAP = 0x6fff4c0e, // LLVM function address map.
// Android's experimental support for SHT_RELR sections.
// https://android.googlesource.com/platform/bionic/+/b7feec74547f84559a1467aca02708ff61346d2a/libc/include/elf.h#512
SHT_ANDROID_RELR = 0x6fffff00, // Relocation entries; only offsets.
diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h
index 5291369b3b9f1d..82ebf0361c13d8 100644
--- a/llvm/include/llvm/CodeGen/AsmPrinter.h
+++ b/llvm/include/llvm/CodeGen/AsmPrinter.h
@@ -414,6 +414,8 @@ class AsmPrinter : public MachineFunctionPass {
void emitBBAddrMapSection(const MachineFunction &MF);
+ void emitFuncAddrMapSection(const MachineFunction &MF);
+
void emitKCFITrapEntry(const MachineFunction &MF, const MCSymbol *Symbol);
virtual void emitKCFITypeId(const MachineFunction &MF);
diff --git a/llvm/include/llvm/MC/MCContext.h b/llvm/include/llvm/MC/MCContext.h
index 57ba40f7ac26fc..8ba1c30d8a499d 100644
--- a/llvm/include/llvm/MC/MCContext.h
+++ b/llvm/include/llvm/MC/MCContext.h
@@ -177,6 +177,9 @@ class MCContext {
/// LLVM_BB_ADDR_MAP version to emit.
uint8_t BBAddrMapVersion = 2;
+ /// LLVM_FUNC_ADDR_MAP version to emit.
+ uint8_t FuncAddrMapVersion = 1;
+
/// The file name of the log file from the environment variable
/// AS_SECURE_LOG_FILE. Which must be set before the .secure_log_unique
/// directive is used or it is an error.
@@ -656,6 +659,8 @@ class MCContext {
uint8_t getBBAddrMapVersion() const { return BBAddrMapVersion; }
+ uint8_t getFuncAddrMapVersion() const { return FuncAddrMapVersion; }
+
/// @}
/// \name Dwarf Management
diff --git a/llvm/include/llvm/MC/MCObjectFileInfo.h b/llvm/include/llvm/MC/MCObjectFileInfo.h
index fb575fe721015c..4bd34947762c01 100644
--- a/llvm/include/llvm/MC/MCObjectFileInfo.h
+++ b/llvm/include/llvm/MC/MCObjectFileInfo.h
@@ -364,6 +364,8 @@ class MCObjectFileInfo {
MCSection *getBBAddrMapSection(const MCSection &TextSec) const;
+ MCSection *getFuncAddrMapSection(const MCSection &TextSec) const;
+
MCSection *getKCFITrapSection(const MCSection &TextSec) const;
MCSection *getPseudoProbeSection(const MCSection &TextSec) const;
diff --git a/llvm/include/llvm/Object/ELF.h b/llvm/include/llvm/Object/ELF.h
index 3aa1d7864fcb70..b179889d601252 100644
--- a/llvm/include/llvm/Object/ELF.h
+++ b/llvm/include/llvm/Object/ELF.h
@@ -513,6 +513,10 @@ class ELFFile {
decodeBBAddrMap(const Elf_Shdr &Sec, const Elf_Shdr *RelaSec = nullptr,
std::vector<PGOAnalysisMap> *PGOAnalyses = nullptr) const;
+ Expected<std::vector<FuncAddrMap>>
+ decodeFuncAddrMap(const Elf_Shdr &Sec,
+ const Elf_Shdr *RelaSec = nullptr) const;
+
/// Returns a map from every section matching \p IsMatch to its relocation
/// section, or \p nullptr if it has no relocation section. This function
/// returns an error if any of the \p IsMatch calls fail or if it fails to
diff --git a/llvm/include/llvm/Object/ELFTypes.h b/llvm/include/llvm/Object/ELFTypes.h
index 87e4dbe4480910..7d79fb82c046f9 100644
--- a/llvm/include/llvm/Object/ELFTypes.h
+++ b/llvm/include/llvm/Object/ELFTypes.h
@@ -1027,6 +1027,44 @@ struct PGOAnalysisMap {
}
};
+// Struct representing the FuncAddrMap for one function.
+struct FuncAddrMap {
+
+ // Bitfield of optional features to control the extra information
+ // emitted/encoded in the the section.
+ struct Features {
+ bool DynamicInstCount : 1;
+
+ // Encodes to minimum bit width representation.
+ uint8_t encode() const {
+ return (static_cast<uint8_t>(DynamicInstCount) << 0);
+ }
+
+ // Decodes from minimum bit width representation and validates no
+ // unnecessary bits are used.
+ static Expected<Features> decode(uint8_t Val) {
+ Features Feat{static_cast<bool>(Val & (1 << 0))};
+ if (Feat.encode() != Val)
+ return createStringError(
+ std::error_code(),
+ "invalid encoding for FuncAddrMap::Features: 0x%x", Val);
+ return Feat;
+ }
+
+ bool operator==(const Features &Other) const {
+ return DynamicInstCount == Other.DynamicInstCount;
+ }
+ };
+
+ uint64_t FunctionAddress = 0; // Function entry address.
+ uint64_t DynamicInstCount = 0; // Dynamic instruction count for this function
+
+ // Flags to indicate if each feature was enabled in this function
+ Features FeatEnable;
+
+ uint64_t getFunctionAddress() const { return FunctionAddress; }
+};
+
} // end namespace object.
} // end namespace llvm.
diff --git a/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h
index dfdfa055d65fa6..80d6a9ff83439a 100644
--- a/llvm/include/llvm/ObjectYAML/ELFYAML.h
+++ b/llvm/include/llvm/ObjectYAML/ELFYAML.h
@@ -195,6 +195,13 @@ struct PGOAnalysisMapEntry {
std::optional<std::vector<PGOBBEntry>> PGOBBEntries;
};
+struct FuncAddrMapEntry {
+ uint8_t Version;
+ llvm::yaml::Hex8 Feature;
+ llvm::yaml::Hex64 Address;
+ llvm::yaml::Hex64 DynamicInstCount;
+};
+
struct StackSizeEntry {
llvm::yaml::Hex64 Address;
llvm::yaml::Hex64 Size;
@@ -229,6 +236,7 @@ struct Chunk {
DependentLibraries,
CallGraphProfile,
BBAddrMap,
+ FuncAddrMap,
// Special chunks.
SpecialChunksStart,
@@ -355,6 +363,20 @@ struct BBAddrMapSection : Section {
}
};
+struct FuncAddrMapSection : Section {
+ std::optional<std::vector<FuncAddrMapEntry>> Entries;
+
+ FuncAddrMapSection() : Section(ChunkKind::FuncAddrMap) {}
+
+ std::vector<std::pair<StringRef, bool>> getEntries() const override {
+ return {{"Entries", Entries.has_value()}};
+ };
+
+ static bool classof(const Chunk *S) {
+ return S->Kind == ChunkKind::FuncAddrMap;
+ }
+};
+
struct StackSizesSection : Section {
std::optional<std::vector<StackSizeEntry>> Entries;
@@ -762,6 +784,7 @@ bool shouldAllocateFileSpace(ArrayRef<ProgramHeader> Phdrs,
} // end namespace llvm
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::StackSizeEntry)
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::FuncAddrMapEntry)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::BBAddrMapEntry)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::BBAddrMapEntry::BBEntry)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::BBAddrMapEntry::BBRangeEntry)
@@ -929,6 +952,10 @@ template <> struct MappingTraits<ELFYAML::StackSizeEntry> {
static void mapping(IO &IO, ELFYAML::StackSizeEntry &Rel);
};
+template <> struct MappingTraits<ELFYAML::FuncAddrMapEntry> {
+ static void mapping(IO &IO, ELFYAML::FuncAddrMapEntry &E);
+};
+
template <> struct MappingTraits<ELFYAML::BBAddrMapEntry> {
static void mapping(IO &IO, ELFYAML::BBAddrMapEntry &E);
};
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index b2a4721f37b268..4c56c306b5fc34 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -147,6 +147,11 @@ enum class PGOMapFeaturesEnum {
BrProb,
All,
};
+
+enum class FuncAddrMapFeaturesEnum {
+ DynamicInstCount,
+};
+
static cl::bits<PGOMapFeaturesEnum> PgoAnalysisMapFeatures(
"pgo-analysis-map", cl::Hidden, cl::CommaSeparated,
cl::values(
@@ -173,6 +178,13 @@ static cl::opt<bool> EmitJumpTableSizesSection(
cl::desc("Emit a section containing jump table addresses and sizes"),
cl::Hidden, cl::init(false));
+static cl::bits<FuncAddrMapFeaturesEnum> FuncAddrMapFeatures(
+ "func-addr-map", cl::Hidden, cl::CommaSeparated,
+ cl::values(clEnumValN(FuncAddrMapFeaturesEnum::DynamicInstCount,
+ "dyn-inst-count", "Dynamic instruction count")),
+ cl::desc("Emit features of function address map in SHT_LLVM_FUNC_ADDR_MAP "
+ "section"));
+
// This isn't turned on by default, since several of the scheduling models are
// not completely accurate, and we don't want to be misleading.
static cl::opt<bool> PrintLatency(
@@ -1390,6 +1402,14 @@ static uint32_t getBBAddrMapMetadata(const MachineBasicBlock &MBB) {
.encode();
}
+static llvm::object::FuncAddrMap::Features getFuncAddrMapFeature() {
+ return {FuncAddrMapFeatures.isSet(FuncAddrMapFeaturesEnum::DynamicInstCount)};
+}
+
+static bool isAnyFuncAddrMapFeature() {
+ return FuncAddrMapFeatures.getBits() != 0;
+}
+
static llvm::object::BBAddrMap::Features
getBBAddrMapFeature(const MachineFunction &MF, int NumMBBSectionRanges) {
// Ensure that the user has not passed in additional options while also
@@ -1424,6 +1444,39 @@ getBBAddrMapFeature(const MachineFunction &MF, int NumMBBSectionRanges) {
static_cast<bool>(BBAddrMapSkipEmitBBEntries)};
}
+void AsmPrinter::emitFuncAddrMapSection(const MachineFunction &MF) {
+ if (!isAnyFuncAddrMapFeature())
+ return;
+
+ MCSection *FuncAddrMapSection =
+ getObjFileLowering().getFuncAddrMapSection(*MF.getSection());
+ assert(FuncAddrMapSection &&
+ ".llvm_func_addr_map section is not initialized.");
+ const MCSymbol *FunctionSymbol = getFunctionBegin();
+ OutStreamer->pushSection();
+ OutStreamer->switchSection(FuncAddrMapSection);
+ OutStreamer->AddComment("version");
+ uint8_t FuncAddrMapVersion =
+ OutStreamer->getContext().getFuncAddrMapVersion();
+ OutStreamer->emitInt8(FuncAddrMapVersion);
+ OutStreamer->AddComment("feature");
+ auto Features = getFuncAddrMapFeature();
+ OutStreamer->emitInt8(Features.encode());
+
+ OutStreamer->AddComment("function address");
+ OutStreamer->emitSymbolValue(FunctionSymbol, getPointerSize());
+ if (Features.DynamicInstCount) {
+ const MachineBlockFrequencyInfo *MBFI =
+ &getAnalysis<LazyMachineBlockFrequencyInfoPass>().getBFI();
+ uint64_t DynInstCount = 0;
+ for (const MachineBasicBlock &MBB : MF)
+ DynInstCount += MBFI->getBlockProfileCount(&MBB).value_or(0) * MBB.size();
+ OutStreamer->AddComment("Dynamic instruction count");
+ OutStreamer->emitULEB128IntValue(DynInstCount);
+ }
+ OutStreamer->popSection();
+}
+
void AsmPrinter::emitBBAddrMapSection(const MachineFunction &MF) {
MCSection *BBAddrMapSection =
getObjFileLowering().getBBAddrMapSection(*MF.getSection());
@@ -2119,6 +2172,8 @@ void AsmPrinter::emitFunctionBody() {
MF->getContext().reportWarning(
SMLoc(), "pgo-analysis-map is enabled for function " + MF->getName() +
" but it does not have labels");
+
+ emitFuncAddrMapSection(*MF);
}
// Emit sections containing instruction and function PCs.
@@ -2749,7 +2804,7 @@ void AsmPrinter::SetupMachineFunction(MachineFunction &MF) {
F.hasFnAttribute("xray-instruction-threshold") ||
needFuncLabels(MF, *this) || NeedsLocalForSize ||
MF.getTarget().Options.EmitStackSizeSection ||
- MF.getTarget().Options.BBAddrMap) {
+ MF.getTarget().Options.BBAddrMap || isAnyFuncAddrMapFeature()) {
CurrentFnBegin = createTempSymbol("func_begin");
if (NeedsLocalForSize)
CurrentFnSymForSize = CurrentFnBegin;
diff --git a/llvm/lib/MC/MCObjectFileInfo.cpp b/llvm/lib/MC/MCObjectFileInfo.cpp
index 150e38a94db6a6..47ed5d91c80849 100644
--- a/llvm/lib/MC/MCObjectFileInfo.cpp
+++ b/llvm/lib/MC/MCObjectFileInfo.cpp
@@ -1120,6 +1120,24 @@ MCObjectFileInfo::getBBAddrMapSection(const MCSection &TextSec) const {
cast<MCSymbolELF>(TextSec.getBeginSymbol()));
}
+MCSection *
+MCObjectFileInfo::getFuncAddrMapSection(const MCSection &TextSec) const {
+ if (Ctx->getObjectFileType() != MCContext::IsELF)
+ return nullptr;
+
+ const MCSectionELF &ElfSec = static_cast<const MCSectionELF &>(TextSec);
+ unsigned Flags = ELF::SHF_LINK_ORDER;
+ StringRef GroupName;
+ if (const MCSymbol *Group = ElfSec.getGroup()) {
+ GroupName = Group->getName();
+ Flags |= ELF::SHF_GROUP;
+ }
+
+ return Ctx->getELFSection(".llvm_func_addr_map", ELF::SHT_LLVM_FUNC_ADDR_MAP,
+ Flags, 0, GroupName, true, ElfSec.getUniqueID(),
+ cast<MCSymbolELF>(TextSec.getBeginSymbol()));
+}
+
MCSection *
MCObjectFileInfo::getKCFITrapSection(const MCSection &TextSec) const {
if (Ctx->getObjectFileType() != MCContext::IsELF)
diff --git a/llvm/lib/MC/MCParser/ELFAsmParser.cpp b/llvm/lib/MC/MCParser/ELFAsmParser.cpp
index b58210b3c268e9..044e9c19f4b777 100644
--- a/llvm/lib/MC/MCParser/ELFAsmParser.cpp
+++ b/llvm/lib/MC/MCParser/ELFAsmParser.cpp
@@ -679,6 +679,8 @@ bool ELFAsmParser::parseSectionArguments(bool IsPush, SMLoc loc) {
Type = ELF::SHT_LLVM_LTO;
else if (TypeName == "llvm_jt_sizes")
Type = ELF::SHT_LLVM_JT_SIZES;
+ else if (TypeName == "llvm_func_addr_map")
+ Type = ELF::SHT_LLVM_FUNC_ADDR_MAP;
else if (TypeName.getAsInteger(0, Type))
return TokError("unknown section type");
}
diff --git a/llvm/lib/MC/MCSectionELF.cpp b/llvm/lib/MC/MCSectionELF.cpp
index 25e62b70b5e2a0..8603ea43ede867 100644
--- a/llvm/lib/MC/MCSectionELF.cpp
+++ b/llvm/lib/MC/MCSectionELF.cpp
@@ -174,6 +174,8 @@ void MCSectionELF::printSwitchToSection(const MCAsmInfo &MAI, const Triple &T,
OS << "llvm_lto";
else if (Type == ELF::SHT_LLVM_JT_SIZES)
OS << "llvm_jt_sizes";
+ else if (Type == ELF::SHT_LLVM_FUNC_ADDR_MAP)
+ OS << "llvm_func_addr_map";
else
OS << "0x" << Twine::utohexstr(Type);
diff --git a/llvm/lib/Object/ELF.cpp b/llvm/lib/Object/ELF.cpp
index b6d0699ee4fe08..bb5e6fa5970125 100644
--- a/llvm/lib/Object/ELF.cpp
+++ b/llvm/lib/Object/ELF.cpp
@@ -320,7 +320,8 @@ StringRef llvm::object::getELFSectionTypeName(uint32_t Machine, unsigned Type) {
STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_BB_ADDR_MAP);
STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_OFFLOADING);
STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_LTO);
- STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_JT_SIZES)
+ STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_JT_SIZES);
+ STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_FUNC_ADDR_MAP);
STRINGIFY_ENUM_CASE(ELF, SHT_GNU_ATTRIBUTES);
STRINGIFY_ENUM_CASE(ELF, SHT_GNU_HASH);
STRINGIFY_ENUM_CASE(ELF, SHT_GNU_verdef);
@@ -731,6 +732,101 @@ static IntTy readULEB128As(DataExtractor &Data, DataExtractor::Cursor &Cur,
return static_cast<IntTy>(Value);
}
+template <typename ELFT>
+static Expected<std::vector<FuncAddrMap>>
+decodeFuncAddrMapImpl(const ELFFile<ELFT> &EF,
+ const typename ELFFile<ELFT>::Elf_Shdr &Sec,
+ const typename ELFFile<ELFT>::Elf_Shdr *RelaSec) {
+ bool IsRelocatable = EF.getHeader().e_type == ELF::ET_REL;
+
+ // This DenseMap maps the offset of each function (the location of the
+ // reference to the function in the SHT_LLVM_FUNC_ADDR_MAP section) to the
+ // addend (the location of the function in the text section).
+ llvm::DenseMap<uint64_t, uint64_t> FunctionOffsetTranslations;
+ if (IsRelocatable && RelaSec) {
+ assert(RelaSec &&
+ "Can't read a SHT_LLVM_FUNC_ADDR_MAP section in a relocatable "
+ "object file without providing a relocation section.");
+ Expected<typename ELFFile<ELFT>::Elf_Rela_Range> Relas = EF.relas(*RelaSec);
+ if (!Relas)
+ return createError("unable to read relocations for section " +
+ describe(EF, Sec) + ": " +
+ toString(Relas.takeError()));
+ for (typename ELFFile<ELFT>::Elf_Rela Rela : *Relas)
+ FunctionOffsetTranslations[Rela.r_offset] = Rela.r_addend;
+ }
+ auto GetAddressForRelocation =
+ [&](unsigned RelocationOffsetInSection) -> Expected<unsigned> {
+ auto FOTIterator =
+ FunctionOffsetTranslations.find(RelocationOffsetInSection);
+ if (FOTIterator == FunctionOffsetTranslations.end()) {
+ return createError("failed to get relocation data for offset: " +
+ Twine::utohexstr(RelocationOffsetInSection) +
+ " in section " + describe(EF, Sec));
+ }
+ return FOTIterator->second;
+ };
+ Expected<ArrayRef<uint8_t>> ContentsOrErr = EF.getSectionContents(Sec);
+ if (!ContentsOrErr)
+ return ContentsOrErr.takeError();
+ ArrayRef<uint8_t> Content = *ContentsOrErr;
+ DataExtractor Data(Content, EF.isLE(), ELFT::Is64Bits ? 8 : 4);
+ std::vector<FuncAddrMap> FunctionEntries;
+
+ DataExtractor::Cursor Cur(0);
+ Error ULEBSizeErr = Error::success();
+
+ // Helper lampda to extract the (possiblly relocatable) address stored at Cur.
+ auto ExtractAddress = [&]() -> Expected<typename ELFFile<ELFT>::uintX_t> {
+ uint64_t RelocationOffsetInSection = Cur.tell();
+ auto Address =
+ static_cast<typename ELFFile<ELFT>::uintX_t>(Data.getAddress(Cur));
+ if (!Cur)
+ return Cur.takeError();
+ if (!IsRelocatable)
+ return Address;
+ assert(Address == 0);
+ Expected<unsigned> AddressOrErr =
+ GetAddressForRelocation(RelocationOffsetInSection);
+ if (!AddressOrErr)
+ return AddressOrErr.takeError();
+ return *AddressOrErr;
+ };
+
+ uint8_t Version = 0;
+ uint8_t Feature = 0;
+ FuncAddrMap::Features FeatEnable{};
+ while (!ULEBSizeErr && Cur && Cur.tell() < Content.size()) {
+ if (Sec.sh_type == ELF::SHT_LLVM_FUNC_ADDR_MAP) {
+ Version = Data.getU8(Cur);
+ if (!Cur)
+ break;
+ Feature = Data.getU8(Cur); // Feature byte
+ if (!Cur)
+ break;
+ auto FeatEnableOrErr = FuncAddrMap::Features::decode(Feature);
+ if (!FeatEnableOrErr)
+ return FeatEnableOrErr.takeError();
+ FeatEnable = *FeatEnableOrErr;
+ }
+ typename ELFFile<ELFT>::uintX_t FunctionAddress = 0;
+ auto AddressOrErr = ExtractAddress();
+ if (!AddressOrErr)
+ return AddressOrErr.takeError();
+ FunctionAddress = *AddressOrErr;
+ uint64_t DynamicInstCount =
+ FeatEnable.DynamicInstCount
+ ? readULEB128As<uint64_t>(Data, Cur, ULEBSizeErr)
+ : 0;
+ FunctionEntries.push_back({FunctionAddress, DynamicInstCount, FeatEnable});
+ }
+ // Either Cur is in the error state, or we have an error in ULEBSizeErr, but
+ // we join all errors here to be safe.
+ if (!Cur || ULEBSizeErr)
+ return joinErrors(Cur.takeError(), std::move(ULEBSizeErr));
+ return FunctionEntries;
+}
+
template <typename ELFT>
static Expected<std::vector<BBAddrMap>>
decodeBBAddrMapImpl(const ELFFile<ELFT> &EF,
@@ -939,6 +1035,14 @@ ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec, const Elf_Shdr *RelaSec,
return std::move(AddrMapsOrErr);
}
+template <class ELFT>
+Expected<std::vector<FuncAddrMap>>
+ELFFile<ELFT>::decodeFuncAddrMap(const Elf_Shdr &Sec,
+ const Elf_Shdr *RelaSec) const {
+ auto AddrMapsOrErr = decodeFuncAddrMapImpl(*this, Sec, RelaSec);
+ return std::move(AddrMapsOrErr);
+}
+
template <class ELFT>
Expected<
MapVector<const typename ELFT::Shdr *, const typename ELFT::Shdr *>>
diff --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp
index cc41bbe6bbde24..2a923515f7ef97 100644
--- a/llvm/lib/ObjectYAML/ELFEmitter.cpp
+++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp
@@ -287,6 +287,9 @@ template <class ELFT> class ELFState {
void writeSectionContent(Elf_Shdr &SHeader,
const ELFYAML::BBAddrMapSection &Section,
ContiguousBlobAccumulator &CBA);
+ void writeSectionContent(Elf_Shdr &SHeader,
+ const ELFYAML::FuncAddrMapSection &Section,
+ ContiguousBlobAccumulator &CBA);
void writeSectionContent(Elf_Shdr &SHeader,
const ELFYAML::HashSection &Section,
ContiguousBlobAccumulator &CBA);
@@ -898,6 +901,8 @@ void ELFState<ELFT>::initSectionHeaders(std::vector<Elf_Shdr> &SHeaders,
writeSectionContent(SHeader, *S, CBA);
} else if (auto S = dyn_cast<ELFYAML::BBAddrMapSection>(Sec)) {
writeSectionContent(SHeader, *S, CBA);
+ } else if (auto S = dyn_cast<ELFYAML::FuncAddrMapSection>(Sec)) {
+ writeSectionContent(SHeader, *S, CBA);
} else {
llvm_unreachable("Unknown section type");
}
@@ -1541,6 +1546,24 @@ void ELFState<ELFT>::writeSectionContent(
}
}
+template <class ELFT>
+void ELFState<ELFT>::writeSectionContent(
+ Elf_Shdr &SHeader, const ELFYAML::FuncAddrMapSection &Section,
+ ContiguousBlobAccumulator &CBA) {
+ for (const auto &[Idx, E] : llvm::enumerate(*Section.Entries)) {
+ // Write version and feature values.
+ if (Section.Type == llvm::ELF::SHT_LLVM_FUNC_ADDR_MAP) {
+ CBA.write(E.Version);
+ CBA.write(E.Feature);
+ SHeader.sh_size += 2;
+ }
+ CBA.write<uintX_t>(E.Address, ELFT::Endianness);
+ SHeader.sh_size += sizeof(uintX_t);
+ if (E.DynamicInstCount)
+ SHeader.sh_size += CBA.writeULEB128(E.DynamicInstCount);
+ }
+}
+
template <class ELFT>
void ELFState<ELFT>::writeSectionContent(
Elf_Shdr &SHeader, const ELFYAML::LinkerOptionsSection &Section,
diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp
index 7e94d01a971534..1c7bbc5239a1b1 100644
--- a/llvm/lib/ObjectYAML/ELFYAML.cpp
+++ b/llvm/lib/ObjectYAML/ELFYAML.cpp
@@ -723,6 +723,7 @@ void ScalarEnumerationTraits<ELFYAML::ELF_SHT>::enumeration(
ECase(SHT_LLVM_PART_PHDR);
ECase(SHT_LLVM_BB_ADDR_MAP_V0);
ECase(SHT_LLVM_BB_ADDR_MAP);
+ ECase(SHT_LLVM_FUNC_ADDR_MAP);
ECase(SHT_LLVM_OFFLOADING);
ECase(SHT_LLVM_LTO);
ECase(SHT_GNU_ATTRIBUTES);
@@ -1425,6 +1426,12 @@ static void sectionMapping(IO &IO, ELFYAML::RawContentSection &Section) {
IO.mapOptional("Info", Section.Info);
}
+static void sectionMapping(IO &IO, ELFYAML::FuncAddrMapSection &Section) {
+ commonSectionMapping(IO, Section);
+ IO.mapOptional("Content", Section.Content);
+ IO.mapOptional("Entries", Section.Entries);
+}
+
static void sectionMapping(IO &IO, ELFYAML::BBAddrMapSection &Section) {
commonSectionMapping(IO, Section);
IO.mapOptional("Content", Section.Content);
@@ -1725,6 +1732,11 @@ void MappingTraits<std::unique_ptr<ELFYAML::Chunk>>::mapping(
Section.reset(new ELFYAML::BBAddrMapSection());
sectionMapping(IO, *cast<ELFYAML::BBAddrMapSection>(Section.get()));
break;
+ case ELF::SHT_LLVM_FUNC_ADDR_MAP:
+ if (!IO.outputting())
+ Section.reset(new ELFYAML::FuncAddrMapSection());
+ sectionMapping(IO, *cast<ELFYAML::FuncAddrMapSection>(Section.get()));
+ break;
default:
if (!IO.outputting()) {
StringRef Name;
@@ -1846,6 +1858,15 @@ void MappingTraits<ELFYAML::StackSizeEntry>::mapping(
IO.mapRequired("Size", E.Size);
}
+void MappingTraits<ELFYAML::FuncAddrMapEntry>::mapping(
+ IO &IO, ELFYAML::FuncAddrMapEntry &E) {
+ assert(IO.getContext() && "The IO context is not initialized");
+ IO.mapRequired("Version", E.Version);
+ IO.mapOptional("Feature", E.Feature, Hex8(0));
+ IO.mapOptional("Address", E.Address, Hex64(0));
+ IO.mapOptional("DynInstCnt", E.DynamicInstCount, Hex64(0));
+}
+
void MappingTraits<ELFYAML::BBAddrMapEntry>::mapping(
IO &IO, ELFYAML::BBAddrMapEntry &E) {
assert(IO.getContext() && "The IO context is not initialized");
diff --git a/llvm/test/CodeGen/X86/function-address-map-function-sections.ll b/llvm/test/CodeGen/X86/function-address-map-function-sections.ll
new file mode 100644
index 00000000000000..4590dfd5da2ff8
--- /dev/null
+++ b/llvm/test/CodeGen/X86/function-address-map-function-sections.ll
@@ -0,0 +1,41 @@
+; RUN: llc < %s -mtriple=x86_64 -function-sections -func-addr-map=dyn-inst-count| FileCheck %s
+
+$_Z4fooTIiET_v = comdat any
+
+define dso_local i32 @_Z3barv() {
+ ret i32 0
+}
+;; Check we add SHF_LINK_ORDER for .llvm_func_addr_map and link it with the corresponding .text sections.
+; CHECK: .section .text._Z3barv,"ax", at progbits
+; CHECK-LABEL: _Z3barv:
+; CHECK-NEXT: [[BAR_BEGIN:.Lfunc_begin[0-9]+]]:
+; CHECK: .section .llvm_func_addr_map,"o", at llvm_func_addr_map,.text._Z3barv{{$}}
+; CHECK-NEXT: .byte 1 # version
+; CHECK-NEXT: .byte 1 # feature
+; CHECK-NEXT: .quad [[BAR_BEGIN]] # function address
+
+
+define dso_local i32 @_Z3foov() {
+ %1 = call i32 @_Z4fooTIiET_v()
+ ret i32 %1
+}
+; CHECK: .section .text._Z3foov,"ax", at progbits
+; CHECK-LABEL: _Z3foov:
+; CHECK-NEXT: [[FOO_BEGIN:.Lfunc_begin[0-9]+]]:
+; CHECK: .section .llvm_func_addr_map,"o", at llvm_func_addr_map,.text._Z3foov{{$}}
+; CHECK-NEXT: .byte 1 # version
+; CHECK-NEXT: .byte 1 # feature
+; CHECK-NEXT: .quad [[FOO_BEGIN]] # function address
+
+
+define linkonce_odr dso_local i32 @_Z4fooTIiET_v() comdat {
+ ret i32 0
+}
+;; Check we add .llvm_func_addr_map section to a COMDAT group with the corresponding .text section if such a COMDAT exists.
+; CHECK: .section .text._Z4fooTIiET_v,"axG", at progbits,_Z4fooTIiET_v,comdat
+; CHECK-LABEL: _Z4fooTIiET_v:
+; CHECK-NEXT: [[FOOCOMDAT_BEGIN:.Lfunc_begin[0-9]+]]:
+; CHECK: .section .llvm_func_addr_map,"oG", at llvm_func_addr_map,.text._Z4fooTIiET_v,_Z4fooTIiET_v,comdat{{$}}
+; CHECK-NEXT: .byte 1 # version
+; CHECK-NEXT: .byte 1 # feature
+; CHECK-NEXT: .quad [[FOOCOMDAT_BEGIN]] # function address
diff --git a/llvm/test/MC/AsmParser/llvm_section_types.s b/llvm/test/MC/AsmParser/llvm_section_types.s
index 147b1499d2b888..ab30a7565104e8 100644
--- a/llvm/test/MC/AsmParser/llvm_section_types.s
+++ b/llvm/test/MC/AsmParser/llvm_section_types.s
@@ -17,6 +17,9 @@
.byte 1
.section .section8,"", at llvm_lto
.byte 1
+.section .section9,"", at llvm_func_addr_map
+.byte 1
+
# CHECK: Name: .section1
# CHECK-NEXT: Type: SHT_LLVM_BB_ADDR_MAP
@@ -34,3 +37,5 @@
# CHECK-NEXT: Type: SHT_LLVM_OFFLOADING
# CHECK: Name: .section8
# CHECK-NEXT: Type: SHT_LLVM_LTO
+# CHECK: Name: .section9
+# CHECK-NEXT: Type: SHT_LLVM_FUNC_ADDR_MAP
diff --git a/llvm/test/tools/llvm-readobj/ELF/func-addr-map.test b/llvm/test/tools/llvm-readobj/ELF/func-addr-map.test
new file mode 100644
index 00000000000000..cf88a5c2dfb62c
--- /dev/null
+++ b/llvm/test/tools/llvm-readobj/ELF/func-addr-map.test
@@ -0,0 +1,96 @@
+## This test checks how we handle the --func-addr-map option.
+
+## Check 64-bit:
+# RUN: yaml2obj --docnum=1 %s -DBITS=64 -DADDR=0x999999999 -o %t1.x64.o
+# RUN: llvm-readobj %t1.x64.o --func-addr-map 2>&1 | FileCheck %s -DADDR=0x999999999 -DFILE=%t1.x64.o --check-prefix=CHECK
+# RUN: llvm-readelf %t1.x64.o --func-addr-map | FileCheck %s --check-prefix=GNU
+
+## Check 32-bit:
+# RUN: yaml2obj --docnum=1 %s -DBITS=32 -o %t1.x32.o
+# RUN: llvm-readobj %t1.x32.o --func-addr-map 2>&1 | FileCheck -DADDR=0x11111 %s -DFILE=%t1.x32.o --check-prefix=CHECK
+# RUN: llvm-readelf %t1.x32.o --func-addr-map | FileCheck %s --check-prefix=GNU
+
+## Check that a malformed section can be handled.
+# RUN: yaml2obj --docnum=1 %s -DBITS=32 -DSIZE=3 -o %t2.o
+# RUN: llvm-readobj %t2.o --func-addr-map 2>&1 | FileCheck %s -DOFFSET=0x3 -DFILE=%t2.o --check-prefix=TRUNCATED
+
+# CHECK: FuncAddrMap [
+# CHECK-NEXT: Function {
+# CHECK-NEXT: At: [[ADDR]]
+# CHECK-NEXT: warning: '[[FILE]]': could not identify function symbol for address ([[ADDR]]) in SHT_LLVM_FUNC_ADDR_MAP section with index 3
+# CHECK-NEXT: Name: <?>
+# CHECK-NEXT: DynamicInstCount: 10
+# CHECK-NEXT: }
+# CHECK-NEXT: Function {
+# CHECK-NEXT: At: 0x22222
+# CHECK-NEXT: Name: foo
+# CHECK-NEXT: DynamicInstCount: 16
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+# CHECK-NEXT: FuncAddrMap [
+# CHECK-NEXT: Function {
+# CHECK-NEXT: At: 0x33333
+# CHECK-NEXT: Name: bar
+# CHECK-NEXT: DynamicInstCount: 10
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+
+# GNU: GNUStyle::printFuncAddrMaps not implemented
+
+# TRUNCATED: FuncAddrMap [
+# TRUNCATED-NEXT: warning: '[[FILE]]': unable to dump SHT_LLVM_FUNC_ADDR_MAP section with index 3: unexpected end of data at offset [[OFFSET]]
+# TRUNCATED-NEXT: ]
+## Check that the other valid section is properly dumped.
+# TRUNCATED-NEXT: FuncAddrMap [
+# TRUNCATED-NEXT: Function {
+# TRUNCATED-NEXT: At: 0x33333
+# TRUNCATED-NEXT: Name: bar
+# TRUNCATED-NEXT: DynamicInstCount: 10
+# TRUNCATED-NEXT: }
+# TRUNCATED-NEXT: ]
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS[[BITS]]
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [SHF_ALLOC]
+ - Name: .text.bar
+ Type: SHT_PROGBITS
+ Flags: [SHF_ALLOC]
+ - Name: .llvm_func_addr_map
+ Type: SHT_LLVM_FUNC_ADDR_MAP
+ ShSize: [[SIZE=<none>]]
+ Link: .text
+ Entries:
+ - Version: 1
+ Feature: 0x1
+ Address: [[ADDR=0x11111]]
+ DynInstCnt: 0xA
+ - Version: 1
+ Feature: 0x1
+ Address: 0x22222
+ DynInstCnt: 0x10
+ - Name: dummy_section
+ Type: SHT_PROGBITS
+ Size: 16
+ - Name: '.llvm_func_addr_map_2'
+ Type: SHT_LLVM_FUNC_ADDR_MAP
+ Link: .text.bar
+ Entries:
+ - Version: 1
+ Feature: 0x1
+ Address: 0x33333
+ DynInstCnt: 0xA
+Symbols:
+ - Name: foo
+ Section: .text
+ Type: STT_FUNC
+ Value: 0x22222
+ - Name: bar
+ Section: .text.bar
+ Type: STT_FUNC
+ Value: 0x33333
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index bfca65aad52b44..26b20733928050 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -606,6 +606,7 @@ template <typename ELFT> class GNUELFDumper : public ELFDumper<ELFT> {
void printVersionDependencySection(const Elf_Shdr *Sec) override;
void printCGProfile() override;
void printBBAddrMaps(bool PrettyPGOAnalysis) override;
+ void printFuncAddrMaps() override;
void printAddrsig() override;
void printNotes() override;
void printELFLinkerOptions() override;
@@ -717,6 +718,7 @@ template <typename ELFT> class LLVMELFDumper : public ELFDumper<ELFT> {
void printVersionDependencySection(const Elf_Shdr *Sec) override;
void printCGProfile() override;
void printBBAddrMaps(bool PrettyPGOAnalysis) override;
+ void printFuncAddrMaps() override;
void printAddrsig() override;
void printNotes() override;
void printELFLinkerOptions() override;
@@ -5199,6 +5201,10 @@ void GNUELFDumper<ELFT>::printBBAddrMaps(bool /*PrettyPGOAnalysis*/) {
OS << "GNUStyle::printBBAddrMaps not implemented\n";
}
+template <class ELFT> void GNUELFDumper<ELFT>::printFuncAddrMaps() {
+ OS << "GNUStyle::printFuncAddrMaps not implemented\n";
+}
+
static Expected<std::vector<uint64_t>> toULEB128Array(ArrayRef<uint8_t> Data) {
std::vector<uint64_t> Ret;
const uint8_t *Cur = Data.begin();
@@ -7784,6 +7790,61 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printCGProfile() {
}
}
+template <class ELFT> void LLVMELFDumper<ELFT>::printFuncAddrMaps() {
+ bool IsRelocatable = this->Obj.getHeader().e_type == ELF::ET_REL;
+ using Elf_Shdr = typename ELFT::Shdr;
+ auto IsMatch = [](const Elf_Shdr &Sec) -> bool {
+ return Sec.sh_type == ELF::SHT_LLVM_FUNC_ADDR_MAP;
+ };
+ Expected<MapVector<const Elf_Shdr *, const Elf_Shdr *>> SecRelocMapOrErr =
+ this->Obj.getSectionAndRelocations(IsMatch);
+ if (!SecRelocMapOrErr) {
+ this->reportUniqueWarning(
+ "failed to get SHT_LLVM_FUNC_ADDR_MAP section(s): " +
+ toString(SecRelocMapOrErr.takeError()));
+ return;
+ }
+
+ for (auto const &[Sec, RelocSec] : *SecRelocMapOrErr) {
+ std::optional<const Elf_Shdr *> FunctionSec;
+ if (IsRelocatable)
+ FunctionSec =
+ unwrapOrError(this->FileName, this->Obj.getSection(Sec->sh_link));
+ ListScope L(W, "FuncAddrMap");
+ if (IsRelocatable && !RelocSec) {
+ this->reportUniqueWarning("unable to get relocation section for " +
+ this->describe(*Sec));
+ continue;
+ }
+ Expected<std::vector<FuncAddrMap>> FuncAddrMapOrErr =
+ this->Obj.decodeFuncAddrMap(*Sec, RelocSec);
+ if (!FuncAddrMapOrErr) {
+ this->reportUniqueWarning("unable to dump " + this->describe(*Sec) +
+ ": " + toString(FuncAddrMapOrErr.takeError()));
+ continue;
+ }
+ for (const auto &AM : *FuncAddrMapOrErr) {
+ DictScope D(W, "Function");
+ W.printHex("At", AM.getFunctionAddress());
+ SmallVector<uint32_t> FuncSymIndex =
+ this->getSymbolIndexesForFunctionAddress(AM.getFunctionAddress(),
+ FunctionSec);
+ std::string FuncName = "<?>";
+ if (FuncSymIndex.empty())
+ this->reportUniqueWarning(
+ "could not identify function symbol for address (0x" +
+ Twine::utohexstr(AM.getFunctionAddress()) + ") in " +
+ this->describe(*Sec));
+ else
+ FuncName = this->getStaticSymbolName(FuncSymIndex.front());
+
+ W.printString("Name", FuncName);
+ if (AM.FeatEnable.DynamicInstCount)
+ W.printNumber("DynamicInstCount", AM.DynamicInstCount);
+ }
+ }
+}
+
template <class ELFT>
void LLVMELFDumper<ELFT>::printBBAddrMaps(bool PrettyPGOAnalysis) {
bool IsRelocatable = this->Obj.getHeader().e_type == ELF::ET_REL;
diff --git a/llvm/tools/llvm-readobj/ObjDumper.h b/llvm/tools/llvm-readobj/ObjDumper.h
index cd744e3bbfb712..28e239f86db667 100644
--- a/llvm/tools/llvm-readobj/ObjDumper.h
+++ b/llvm/tools/llvm-readobj/ObjDumper.h
@@ -132,6 +132,7 @@ class ObjDumper {
// If PrettyPGOAnalysis is true, prints BFI as relative frequency and BPI as
// percentage. Otherwise raw values are displayed.
virtual void printBBAddrMaps(bool PrettyPGOAnalysis) {}
+ virtual void printFuncAddrMaps() {}
virtual void printAddrsig() {}
virtual void printNotes() {}
virtual void printELFLinkerOptions() {}
diff --git a/llvm/tools/llvm-readobj/Opts.td b/llvm/tools/llvm-readobj/Opts.td
index 7d574d875d22ea..1cd806d40f89c4 100644
--- a/llvm/tools/llvm-readobj/Opts.td
+++ b/llvm/tools/llvm-readobj/Opts.td
@@ -18,6 +18,7 @@ def all : FF<"all", "Equivalent to setting: --file-header, --program-headers, --
"--symbols, --relocations, --dynamic-table, --notes, --version-info, --unwind, "
"--section-groups and --histogram">;
def arch_specific : FF<"arch-specific", "Display architecture-specific information">;
+def func_addr_map : FF<"func-addr-map", "Display the function address map section">;
def bb_addr_map : FF<"bb-addr-map", "Display the BB address map section">;
def pretty_pgo_analysis_map : FF<"pretty-pgo-analysis-map", "Display PGO analysis values with formatting rather than raw numbers">;
def cg_profile : FF<"cg-profile", "Display call graph profile section">;
diff --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp
index 2f77e5d350553d..588744dc8bf69f 100644
--- a/llvm/tools/llvm-readobj/llvm-readobj.cpp
+++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp
@@ -98,6 +98,7 @@ static bool All;
static bool ArchSpecificInfo;
static bool BBAddrMap;
static bool PrettyPGOAnalysisMap;
+static bool FuncAddrMap;
bool ExpandRelocs;
static bool CGProfile;
static bool Decompress;
@@ -219,6 +220,7 @@ static void parseOptions(const opt::InputArgList &Args) {
WithColor::warning(errs(), ToolName)
<< "--bb-addr-map must be enabled for --pretty-pgo-analysis-map to "
"have an effect\n";
+ opts::FuncAddrMap = Args.hasArg(OPT_func_addr_map);
opts::CGProfile = Args.hasArg(OPT_cg_profile);
opts::Decompress = Args.hasArg(OPT_decompress);
opts::Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, false);
@@ -473,6 +475,8 @@ static void dumpObject(ObjectFile &Obj, ScopedPrinter &Writer,
Dumper->printCGProfile();
if (opts::BBAddrMap)
Dumper->printBBAddrMaps(opts::PrettyPGOAnalysisMap);
+ if (opts::FuncAddrMap)
+ Dumper->printFuncAddrMaps();
if (opts::Addrsig)
Dumper->printAddrsig();
if (opts::Notes)
diff --git a/llvm/tools/obj2yaml/elf2yaml.cpp b/llvm/tools/obj2yaml/elf2yaml.cpp
index b1c8032ea21929..95343351385448 100644
--- a/llvm/tools/obj2yaml/elf2yaml.cpp
+++ b/llvm/tools/obj2yaml/elf2yaml.cpp
@@ -97,6 +97,8 @@ class ELFDumper {
dumpStackSizesSection(const Elf_Shdr *Shdr);
Expected<ELFYAML::BBAddrMapSection *>
dumpBBAddrMapSection(const Elf_Shdr *Shdr);
+ Expected<ELFYAML::FuncAddrMapSection *>
+ dumpFuncAddrMapSection(const Elf_Shdr *Shdr);
Expected<ELFYAML::RawContentSection *>
dumpPlaceholderSection(const Elf_Shdr *Shdr);
@@ -629,6 +631,8 @@ ELFDumper<ELFT>::dumpSections() {
[this](const Elf_Shdr *S) { return dumpCallGraphProfileSection(S); };
case ELF::SHT_LLVM_BB_ADDR_MAP:
return [this](const Elf_Shdr *S) { return dumpBBAddrMapSection(S); };
+ case ELF::SHT_LLVM_FUNC_ADDR_MAP:
+ return [this](const Elf_Shdr *S) { return dumpFuncAddrMapSection(S); };
case ELF::SHT_STRTAB:
case ELF::SHT_SYMTAB:
case ELF::SHT_DYNSYM:
@@ -989,6 +993,55 @@ ELFDumper<ELFT>::dumpBBAddrMapSection(const Elf_Shdr *Shdr) {
return S.release();
}
+template <class ELFT>
+Expected<ELFYAML::FuncAddrMapSection *>
+ELFDumper<ELFT>::dumpFuncAddrMapSection(const Elf_Shdr *Shdr) {
+ auto S = std::make_unique<ELFYAML::FuncAddrMapSection>();
+ if (Error E = dumpCommonSection(Shdr, *S))
+ return std::move(E);
+
+ auto ContentOrErr = Obj.getSectionContents(*Shdr);
+ if (!ContentOrErr)
+ return ContentOrErr.takeError();
+
+ ArrayRef<uint8_t> Content = *ContentOrErr;
+ if (Content.empty())
+ return S.release();
+
+ DataExtractor Data(Content, Obj.isLE(), ELFT::Is64Bits ? 8 : 4);
+
+ std::vector<ELFYAML::FuncAddrMapEntry> Entries;
+ DataExtractor::Cursor Cur(0);
+ uint8_t Version = 0;
+ uint8_t Feature = 0;
+ uint64_t Address = 0;
+ while (Cur && Cur.tell() < Content.size()) {
+ if (Shdr->sh_type == ELF::SHT_LLVM_FUNC_ADDR_MAP) {
+ Version = Data.getU8(Cur);
+ Feature = Data.getU8(Cur);
+ }
+ auto FeatureOrErr = llvm::object::FuncAddrMap::Features::decode(Feature);
+ if (!FeatureOrErr)
+ return FeatureOrErr.takeError();
+
+ Address = Data.getAddress(Cur);
+
+ uint64_t DynamicInstCount =
+ FeatureOrErr->DynamicInstCount ? Data.getULEB128(Cur) : 0;
+ Entries.push_back({Version, Feature, Address, DynamicInstCount});
+ }
+
+ if (!Cur) {
+ // If the section cannot be decoded, we dump it as an array of bytes.
+ consumeError(Cur.takeError());
+ S->Content = yaml::BinaryRef(Content);
+ } else {
+ S->Entries = std::move(Entries);
+ }
+
+ return S.release();
+}
+
template <class ELFT>
Expected<ELFYAML::AddrsigSection *>
ELFDumper<ELFT>::dumpAddrsigSection(const Elf_Shdr *Shdr) {
More information about the llvm-commits
mailing list