mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 02:33:06 +01:00
[llvm-readelf] Support dumping the BB address map section with --bb-addr-map.
This patch lets llvm-readelf dump the content of the BB address map section in the following format: ``` Function { At: <address> BB entries [ { Offset: <offset> Size: <size> Metadata: <metadata> }, ... ] } ... ``` Reviewed By: jhenderson Differential Revision: https://reviews.llvm.org/D95511
This commit is contained in:
parent
2ab41c0cda
commit
2c790c2f9f
@ -32,6 +32,11 @@ OPTIONS
|
|||||||
|
|
||||||
Display architecture-specific information, e.g. the ARM attributes section on ARM.
|
Display architecture-specific information, e.g. the ARM attributes section on ARM.
|
||||||
|
|
||||||
|
.. option:: --bb-addr-map
|
||||||
|
|
||||||
|
Display the contents of the basic block address map section(s), which contain the
|
||||||
|
address of each function, along with the relative offset of each basic block.
|
||||||
|
|
||||||
.. option:: --color
|
.. option:: --color
|
||||||
|
|
||||||
Use colors in the output for warnings and errors.
|
Use colors in the output for warnings and errors.
|
||||||
|
@ -148,6 +148,11 @@ The following options are implemented only for the ELF file format.
|
|||||||
|
|
||||||
Display architecture-specific information, e.g. the ARM attributes section on ARM.
|
Display architecture-specific information, e.g. the ARM attributes section on ARM.
|
||||||
|
|
||||||
|
.. option:: --bb-addr-map
|
||||||
|
|
||||||
|
Display the contents of the basic block address map section(s), which contain the
|
||||||
|
address of each function, along with the relative offset of each basic block.
|
||||||
|
|
||||||
.. option:: --demangle, -C
|
.. option:: --demangle, -C
|
||||||
|
|
||||||
Display demangled symbol names in the output.
|
Display demangled symbol names in the output.
|
||||||
|
@ -392,6 +392,8 @@ public:
|
|||||||
Expected<ArrayRef<T>> getSectionContentsAsArray(const Elf_Shdr &Sec) const;
|
Expected<ArrayRef<T>> getSectionContentsAsArray(const Elf_Shdr &Sec) const;
|
||||||
Expected<ArrayRef<uint8_t>> getSectionContents(const Elf_Shdr &Sec) const;
|
Expected<ArrayRef<uint8_t>> getSectionContents(const Elf_Shdr &Sec) const;
|
||||||
Expected<ArrayRef<uint8_t>> getSegmentContents(const Elf_Phdr &Phdr) const;
|
Expected<ArrayRef<uint8_t>> getSegmentContents(const Elf_Phdr &Phdr) const;
|
||||||
|
Expected<std::vector<Elf_BBAddrMap>>
|
||||||
|
decodeBBAddrMap(const Elf_Shdr &Sec) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
using ELF32LEFile = ELFFile<ELF32LE>;
|
using ELF32LEFile = ELFFile<ELF32LE>;
|
||||||
|
@ -43,6 +43,7 @@ template <class ELFT> struct Elf_Nhdr_Impl;
|
|||||||
template <class ELFT> class Elf_Note_Impl;
|
template <class ELFT> class Elf_Note_Impl;
|
||||||
template <class ELFT> class Elf_Note_Iterator_Impl;
|
template <class ELFT> class Elf_Note_Iterator_Impl;
|
||||||
template <class ELFT> struct Elf_CGProfile_Impl;
|
template <class ELFT> struct Elf_CGProfile_Impl;
|
||||||
|
template <class ELFT> struct Elf_BBAddrMap_Impl;
|
||||||
|
|
||||||
template <endianness E, bool Is64> struct ELFType {
|
template <endianness E, bool Is64> struct ELFType {
|
||||||
private:
|
private:
|
||||||
@ -74,6 +75,7 @@ public:
|
|||||||
using Note = Elf_Note_Impl<ELFType<E, Is64>>;
|
using Note = Elf_Note_Impl<ELFType<E, Is64>>;
|
||||||
using NoteIterator = Elf_Note_Iterator_Impl<ELFType<E, Is64>>;
|
using NoteIterator = Elf_Note_Iterator_Impl<ELFType<E, Is64>>;
|
||||||
using CGProfile = Elf_CGProfile_Impl<ELFType<E, Is64>>;
|
using CGProfile = Elf_CGProfile_Impl<ELFType<E, Is64>>;
|
||||||
|
using BBAddrMap = Elf_BBAddrMap_Impl<ELFType<E, Is64>>;
|
||||||
using DynRange = ArrayRef<Dyn>;
|
using DynRange = ArrayRef<Dyn>;
|
||||||
using ShdrRange = ArrayRef<Shdr>;
|
using ShdrRange = ArrayRef<Shdr>;
|
||||||
using SymRange = ArrayRef<Sym>;
|
using SymRange = ArrayRef<Sym>;
|
||||||
@ -128,13 +130,14 @@ using ELF64BE = ELFType<support::big, true>;
|
|||||||
using Elf_Note = typename ELFT::Note; \
|
using Elf_Note = typename ELFT::Note; \
|
||||||
using Elf_Note_Iterator = typename ELFT::NoteIterator; \
|
using Elf_Note_Iterator = typename ELFT::NoteIterator; \
|
||||||
using Elf_CGProfile = typename ELFT::CGProfile; \
|
using Elf_CGProfile = typename ELFT::CGProfile; \
|
||||||
|
using Elf_BBAddrMap = typename ELFT::BBAddrMap; \
|
||||||
using Elf_Dyn_Range = typename ELFT::DynRange; \
|
using Elf_Dyn_Range = typename ELFT::DynRange; \
|
||||||
using Elf_Shdr_Range = typename ELFT::ShdrRange; \
|
using Elf_Shdr_Range = typename ELFT::ShdrRange; \
|
||||||
using Elf_Sym_Range = typename ELFT::SymRange; \
|
using Elf_Sym_Range = typename ELFT::SymRange; \
|
||||||
using Elf_Rel_Range = typename ELFT::RelRange; \
|
using Elf_Rel_Range = typename ELFT::RelRange; \
|
||||||
using Elf_Rela_Range = typename ELFT::RelaRange; \
|
using Elf_Rela_Range = typename ELFT::RelaRange; \
|
||||||
using Elf_Relr_Range = typename ELFT::RelrRange; \
|
using Elf_Relr_Range = typename ELFT::RelrRange; \
|
||||||
using Elf_Phdr_Range = typename ELFT::PhdrRange; \
|
using Elf_Phdr_Range = typename ELFT::PhdrRange;
|
||||||
|
|
||||||
#define LLVM_ELF_COMMA ,
|
#define LLVM_ELF_COMMA ,
|
||||||
#define LLVM_ELF_IMPORT_TYPES(E, W) \
|
#define LLVM_ELF_IMPORT_TYPES(E, W) \
|
||||||
@ -788,6 +791,28 @@ template <class ELFT> struct Elf_Mips_ABIFlags {
|
|||||||
Elf_Word flags2; // General flags
|
Elf_Word flags2; // General flags
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Struct representing the BBAddrMap for one function.
|
||||||
|
template <class ELFT> struct Elf_BBAddrMap_Impl {
|
||||||
|
LLVM_ELF_IMPORT_TYPES_ELFT(ELFT)
|
||||||
|
uintX_t Addr; // Function address
|
||||||
|
// Struct representing the BBAddrMap information for one basic block.
|
||||||
|
struct BBEntry {
|
||||||
|
uint32_t Offset; // Offset of basic block relative to function start.
|
||||||
|
uint32_t Size; // Size of the basic block.
|
||||||
|
|
||||||
|
// The following fields are decoded from the Metadata field. The encoding
|
||||||
|
// happens in AsmPrinter.cpp:getBBAddrMapMetadata.
|
||||||
|
bool HasReturn; // If this block ends with a return (or tail call).
|
||||||
|
bool HasTailCall; // If this block ends with a tail call.
|
||||||
|
bool IsEHPad; // If this is an exception handling block.
|
||||||
|
|
||||||
|
BBEntry(uint32_t Offset, uint32_t Size, uint32_t Metadata)
|
||||||
|
: Offset(Offset), Size(Size), HasReturn(Metadata & 1),
|
||||||
|
HasTailCall(Metadata & (1 << 1)), IsEHPad(Metadata & (1 << 2)){};
|
||||||
|
};
|
||||||
|
std::vector<BBEntry> BBEntries; // Basic block entries for this function.
|
||||||
|
};
|
||||||
|
|
||||||
} // end namespace object.
|
} // end namespace object.
|
||||||
} // end namespace llvm.
|
} // end namespace llvm.
|
||||||
|
|
||||||
|
@ -161,7 +161,7 @@ struct BBAddrMapEntry {
|
|||||||
llvm::yaml::Hex64 Metadata;
|
llvm::yaml::Hex64 Metadata;
|
||||||
};
|
};
|
||||||
llvm::yaml::Hex64 Address;
|
llvm::yaml::Hex64 Address;
|
||||||
Optional<uint32_t> NumBlocks;
|
Optional<uint64_t> NumBlocks;
|
||||||
Optional<std::vector<BBEntry>> BBEntries;
|
Optional<std::vector<BBEntry>> BBEntries;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -612,6 +612,58 @@ ELFFile<ELFT>::toMappedAddr(uint64_t VAddr, WarningHandler WarnHandler) const {
|
|||||||
return base() + Offset;
|
return base() + Offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class ELFT>
|
||||||
|
Expected<std::vector<typename ELFT::BBAddrMap>>
|
||||||
|
ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec) const {
|
||||||
|
Expected<ArrayRef<uint8_t>> ContentsOrErr = getSectionContents(Sec);
|
||||||
|
if (!ContentsOrErr)
|
||||||
|
return ContentsOrErr.takeError();
|
||||||
|
ArrayRef<uint8_t> Content = *ContentsOrErr;
|
||||||
|
DataExtractor Data(Content, isLE(), ELFT::Is64Bits ? 8 : 4);
|
||||||
|
std::vector<Elf_BBAddrMap> FunctionEntries;
|
||||||
|
|
||||||
|
DataExtractor::Cursor Cur(0);
|
||||||
|
Error ULEBSizeErr = Error::success();
|
||||||
|
|
||||||
|
// Helper to extract and decode the next ULEB128 value as uint32_t.
|
||||||
|
// Returns zero and sets ULEBSizeErr if the ULEB128 value exceeds the uint32_t
|
||||||
|
// limit.
|
||||||
|
// Also returns zero if ULEBSizeErr is already in an error state.
|
||||||
|
auto ReadULEB128AsUInt32 = [&Data, &Cur, &ULEBSizeErr]() -> uint32_t {
|
||||||
|
// Bail out and do not extract data if ULEBSizeErr is already set.
|
||||||
|
if (ULEBSizeErr)
|
||||||
|
return 0;
|
||||||
|
uint64_t Offset = Cur.tell();
|
||||||
|
uint64_t Value = Data.getULEB128(Cur);
|
||||||
|
if (Value > UINT32_MAX) {
|
||||||
|
ULEBSizeErr = createError(
|
||||||
|
"ULEB128 value at offset 0x" + Twine::utohexstr(Offset) +
|
||||||
|
" exceeds UINT32_MAX (0x" + Twine::utohexstr(Value) + ")");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return static_cast<uint32_t>(Value);
|
||||||
|
};
|
||||||
|
|
||||||
|
while (!ULEBSizeErr && Cur && Cur.tell() < Content.size()) {
|
||||||
|
uintX_t Address = static_cast<uintX_t>(Data.getAddress(Cur));
|
||||||
|
uint32_t NumBlocks = ReadULEB128AsUInt32();
|
||||||
|
std::vector<typename Elf_BBAddrMap::BBEntry> BBEntries;
|
||||||
|
for (uint32_t BlockID = 0; !ULEBSizeErr && Cur && (BlockID < NumBlocks);
|
||||||
|
++BlockID) {
|
||||||
|
uint32_t Offset = ReadULEB128AsUInt32();
|
||||||
|
uint32_t Size = ReadULEB128AsUInt32();
|
||||||
|
uint32_t Metadata = ReadULEB128AsUInt32();
|
||||||
|
BBEntries.push_back({Offset, Size, Metadata});
|
||||||
|
}
|
||||||
|
FunctionEntries.push_back({Address, BBEntries});
|
||||||
|
}
|
||||||
|
// Either Cur is in the error state, or ULEBSizeError is set (not both), but
|
||||||
|
// we join the two errors here to be safe.
|
||||||
|
if (!Cur || ULEBSizeErr)
|
||||||
|
return joinErrors(Cur.takeError(), std::move(ULEBSizeErr));
|
||||||
|
return FunctionEntries;
|
||||||
|
}
|
||||||
|
|
||||||
template class llvm::object::ELFFile<ELF32LE>;
|
template class llvm::object::ELFFile<ELF32LE>;
|
||||||
template class llvm::object::ELFFile<ELF32BE>;
|
template class llvm::object::ELFFile<ELF32BE>;
|
||||||
template class llvm::object::ELFFile<ELF64LE>;
|
template class llvm::object::ELFFile<ELF64LE>;
|
||||||
|
119
test/tools/llvm-readobj/ELF/bb-addr-map.test
Normal file
119
test/tools/llvm-readobj/ELF/bb-addr-map.test
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
## This test checks how we handle the --bb-addr-map option.
|
||||||
|
|
||||||
|
## Check 64-bit:
|
||||||
|
# RUN: yaml2obj %s -DBITS=64 -DADDR=0xFFFFFFFF1 -o %t1.x64.o
|
||||||
|
# RUN: llvm-readobj %t1.x64.o --bb-addr-map | FileCheck %s -DADDR=0xFFFFFFFF1 --check-prefix=LLVM
|
||||||
|
# RUN: llvm-readelf %t1.x64.o --bb-addr-map | FileCheck %s --check-prefix=GNU
|
||||||
|
|
||||||
|
## Check 32-bit:
|
||||||
|
# RUN: yaml2obj %s -DBITS=32 -o %t1.x32.o
|
||||||
|
# RUN: llvm-readobj %t1.x32.o --bb-addr-map | FileCheck -DADDR=0x11111 %s --check-prefix=LLVM
|
||||||
|
# RUN: llvm-readelf %t1.x32.o --bb-addr-map | FileCheck %s --check-prefix=GNU
|
||||||
|
|
||||||
|
## Check that a malformed section can be handled.
|
||||||
|
# RUN: yaml2obj %s -DBITS=32 -DSIZE=4 -o %t2.o
|
||||||
|
# RUN: llvm-readobj %t2.o --bb-addr-map 2>&1 | FileCheck %s -DOFFSET=0x00000004 -DFILE=%t2.o --check-prefix=TRUNCATED
|
||||||
|
|
||||||
|
# LLVM: BBAddrMap [
|
||||||
|
# LLVM-NEXT: Function {
|
||||||
|
# LLVM-NEXT: At: [[ADDR]]
|
||||||
|
# LLVM-NEXT: BB entries [
|
||||||
|
# LLVM-NEXT: {
|
||||||
|
# LLVM-NEXT: Offset: 0x0
|
||||||
|
# LLVM-NEXT: Size: 0x1
|
||||||
|
# LLVM-NEXT: HasReturn: No
|
||||||
|
# LLVM-NEXT: HasTailCall: Yes
|
||||||
|
# LLVM-NEXT: IsEHPad: No
|
||||||
|
# LLVM-NEXT: }
|
||||||
|
# LLVM-NEXT: {
|
||||||
|
# LLVM-NEXT: Offset: 0x3
|
||||||
|
# LLVM-NEXT: Size: 0x4
|
||||||
|
# LLVM-NEXT: HasReturn: Yes
|
||||||
|
# LLVM-NEXT: HasTailCall: No
|
||||||
|
# LLVM-NEXT: IsEHPad: Yes
|
||||||
|
# LLVM-NEXT: }
|
||||||
|
# LLVM-NEXT: ]
|
||||||
|
# LLVM-NEXT: }
|
||||||
|
# LLVM-NEXT: Function {
|
||||||
|
# LLVM-NEXT: At: 0x22222
|
||||||
|
# LLVM-NEXT: BB entries [
|
||||||
|
# LLVM-NEXT: {
|
||||||
|
# LLVM-NEXT: Offset: 0x6
|
||||||
|
# LLVM-NEXT: Size: 0x7
|
||||||
|
# LLVM-NEXT: HasReturn: No
|
||||||
|
# LLVM-NEXT: HasTailCall: No
|
||||||
|
# LLVM-NEXT: IsEHPad: No
|
||||||
|
# LLVM-NEXT: }
|
||||||
|
# LLVM-NEXT: ]
|
||||||
|
# LLVM-NEXT: }
|
||||||
|
# LLVM-NEXT: ]
|
||||||
|
# LLVM-NEXT: BBAddrMap [
|
||||||
|
# LLVM-NEXT: Function {
|
||||||
|
# LLVM-NEXT: At: 0x33333
|
||||||
|
# LLVM-NEXT: BB entries [
|
||||||
|
# LLVM-NEXT: {
|
||||||
|
# LLVM-NEXT: Offset: 0x9
|
||||||
|
# LLVM-NEXT: Size: 0xA
|
||||||
|
# LLVM-NEXT: HasReturn: Yes
|
||||||
|
# LLVM-NEXT: HasTailCall: Yes
|
||||||
|
# LLVM-NEXT: IsEHPad: No
|
||||||
|
# LLVM-NEXT: }
|
||||||
|
# LLVM-NEXT: ]
|
||||||
|
# LLVM-NEXT: }
|
||||||
|
# LLVM-NEXT: ]
|
||||||
|
|
||||||
|
# GNU: GNUStyle::printBBAddrMaps not implemented
|
||||||
|
|
||||||
|
# TRUNCATED: BBAddrMap [
|
||||||
|
# TRUNCATED-NEXT: warning: '[[FILE]]': unable to dump SHT_LLVM_BB_ADDR_MAP section with index 1: unable to decode LEB128 at offset [[OFFSET]]: malformed uleb128, extends past end
|
||||||
|
# TRUNCATED-NEXT: ]
|
||||||
|
## Check that the other valid section is properly dumped.
|
||||||
|
# TRUNCATED-NEXT: BBAddrMap [
|
||||||
|
# TRUNCATED-NEXT: Function {
|
||||||
|
# TRUNCATED-NEXT: At: 0x33333
|
||||||
|
# TRUNCATED-NEXT: BB entries [
|
||||||
|
# TRUNCATED-NEXT: {
|
||||||
|
# TRUNCATED-NEXT: Offset: 0x9
|
||||||
|
# TRUNCATED-NEXT: Size: 0xA
|
||||||
|
# TRUNCATED-NEXT: HasReturn: Yes
|
||||||
|
# TRUNCATED-NEXT: HasTailCall: Yes
|
||||||
|
# TRUNCATED-NEXT: IsEHPad: No
|
||||||
|
# TRUNCATED-NEXT: }
|
||||||
|
# TRUNCATED-NEXT: ]
|
||||||
|
# TRUNCATED-NEXT: }
|
||||||
|
# TRUNCATED-NEXT: ]
|
||||||
|
|
||||||
|
--- !ELF
|
||||||
|
FileHeader:
|
||||||
|
Class: ELFCLASS[[BITS]]
|
||||||
|
Data: ELFDATA2LSB
|
||||||
|
Type: ET_EXEC
|
||||||
|
Sections:
|
||||||
|
- Name: bb_addr_map_1
|
||||||
|
Type: SHT_LLVM_BB_ADDR_MAP
|
||||||
|
ShSize: [[SIZE=<none>]]
|
||||||
|
Entries:
|
||||||
|
- Address: [[ADDR=0x11111]]
|
||||||
|
BBEntries:
|
||||||
|
- AddressOffset: 0x0
|
||||||
|
Size: 0x1
|
||||||
|
Metadata: 0xF0000002
|
||||||
|
- AddressOffset: 0x3
|
||||||
|
Size: 0x4
|
||||||
|
Metadata: 0x5
|
||||||
|
- Address: 0x22222
|
||||||
|
BBEntries:
|
||||||
|
- AddressOffset: 0x6
|
||||||
|
Size: 0x7
|
||||||
|
Metadata: 0x8
|
||||||
|
- Name: dummy_section
|
||||||
|
Type: SHT_PROGBITS
|
||||||
|
Size: 16
|
||||||
|
- Name: bb_addr_map_2
|
||||||
|
Type: SHT_LLVM_BB_ADDR_MAP
|
||||||
|
Entries:
|
||||||
|
- Address: 0x33333
|
||||||
|
BBEntries:
|
||||||
|
- AddressOffset: 0x9
|
||||||
|
Size: 0xa
|
||||||
|
Metadata: 0xb
|
@ -550,6 +550,7 @@ public:
|
|||||||
void printVersionDependencySection(const Elf_Shdr *Sec) override;
|
void printVersionDependencySection(const Elf_Shdr *Sec) override;
|
||||||
void printHashHistograms() override;
|
void printHashHistograms() override;
|
||||||
void printCGProfile() override;
|
void printCGProfile() override;
|
||||||
|
void printBBAddrMaps() override;
|
||||||
void printAddrsig() override;
|
void printAddrsig() override;
|
||||||
void printNotes() override;
|
void printNotes() override;
|
||||||
void printELFLinkerOptions() override;
|
void printELFLinkerOptions() override;
|
||||||
@ -660,6 +661,7 @@ public:
|
|||||||
void printVersionDependencySection(const Elf_Shdr *Sec) override;
|
void printVersionDependencySection(const Elf_Shdr *Sec) override;
|
||||||
void printHashHistograms() override;
|
void printHashHistograms() override;
|
||||||
void printCGProfile() override;
|
void printCGProfile() override;
|
||||||
|
void printBBAddrMaps() override;
|
||||||
void printAddrsig() override;
|
void printAddrsig() override;
|
||||||
void printNotes() override;
|
void printNotes() override;
|
||||||
void printELFLinkerOptions() override;
|
void printELFLinkerOptions() override;
|
||||||
@ -4617,6 +4619,10 @@ template <class ELFT> void GNUELFDumper<ELFT>::printCGProfile() {
|
|||||||
OS << "GNUStyle::printCGProfile not implemented\n";
|
OS << "GNUStyle::printCGProfile not implemented\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class ELFT> void GNUELFDumper<ELFT>::printBBAddrMaps() {
|
||||||
|
OS << "GNUStyle::printBBAddrMaps not implemented\n";
|
||||||
|
}
|
||||||
|
|
||||||
static Expected<std::vector<uint64_t>> toULEB128Array(ArrayRef<uint8_t> Data) {
|
static Expected<std::vector<uint64_t>> toULEB128Array(ArrayRef<uint8_t> Data) {
|
||||||
std::vector<uint64_t> Ret;
|
std::vector<uint64_t> Ret;
|
||||||
const uint8_t *Cur = Data.begin();
|
const uint8_t *Cur = Data.begin();
|
||||||
@ -6520,6 +6526,34 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printCGProfile() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class ELFT> void LLVMELFDumper<ELFT>::printBBAddrMaps() {
|
||||||
|
for (const Elf_Shdr &Sec : cantFail(this->Obj.sections())) {
|
||||||
|
if (Sec.sh_type != SHT_LLVM_BB_ADDR_MAP)
|
||||||
|
continue;
|
||||||
|
ListScope L(W, "BBAddrMap");
|
||||||
|
Expected<std::vector<Elf_BBAddrMap>> BBAddrMapOrErr =
|
||||||
|
this->Obj.decodeBBAddrMap(Sec);
|
||||||
|
if (!BBAddrMapOrErr) {
|
||||||
|
this->reportUniqueWarning("unable to dump " + this->describe(Sec) + ": " +
|
||||||
|
toString(BBAddrMapOrErr.takeError()));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (const Elf_BBAddrMap &AM : *BBAddrMapOrErr) {
|
||||||
|
DictScope D(W, "Function");
|
||||||
|
W.printHex("At", AM.Addr);
|
||||||
|
ListScope L(W, "BB entries");
|
||||||
|
for (const typename Elf_BBAddrMap::BBEntry &BBE : AM.BBEntries) {
|
||||||
|
DictScope L(W);
|
||||||
|
W.printHex("Offset", BBE.Offset);
|
||||||
|
W.printHex("Size", BBE.Size);
|
||||||
|
W.printBoolean("HasReturn", BBE.HasReturn);
|
||||||
|
W.printBoolean("HasTailCall", BBE.HasTailCall);
|
||||||
|
W.printBoolean("IsEHPad", BBE.IsEHPad);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template <class ELFT> void LLVMELFDumper<ELFT>::printAddrsig() {
|
template <class ELFT> void LLVMELFDumper<ELFT>::printAddrsig() {
|
||||||
ListScope L(W, "Addrsig");
|
ListScope L(W, "Addrsig");
|
||||||
if (!this->DotAddrsigSec)
|
if (!this->DotAddrsigSec)
|
||||||
|
@ -72,6 +72,7 @@ public:
|
|||||||
virtual void printGroupSections() {}
|
virtual void printGroupSections() {}
|
||||||
virtual void printHashHistograms() {}
|
virtual void printHashHistograms() {}
|
||||||
virtual void printCGProfile() {}
|
virtual void printCGProfile() {}
|
||||||
|
virtual void printBBAddrMaps() {}
|
||||||
virtual void printAddrsig() {}
|
virtual void printAddrsig() {}
|
||||||
virtual void printNotes() {}
|
virtual void printNotes() {}
|
||||||
virtual void printELFLinkerOptions() {}
|
virtual void printELFLinkerOptions() {}
|
||||||
|
@ -367,6 +367,10 @@ namespace opts {
|
|||||||
cl::alias ELFCGProfile("elf-cg-profile", cl::desc("Alias for --cg-profile"),
|
cl::alias ELFCGProfile("elf-cg-profile", cl::desc("Alias for --cg-profile"),
|
||||||
cl::aliasopt(CGProfile));
|
cl::aliasopt(CGProfile));
|
||||||
|
|
||||||
|
// --bb-addr-map
|
||||||
|
cl::opt<bool> BBAddrMap("bb-addr-map",
|
||||||
|
cl::desc("Display the BB address map section"));
|
||||||
|
|
||||||
// -addrsig
|
// -addrsig
|
||||||
cl::opt<bool> Addrsig("addrsig",
|
cl::opt<bool> Addrsig("addrsig",
|
||||||
cl::desc("Display address-significance table"));
|
cl::desc("Display address-significance table"));
|
||||||
@ -542,6 +546,8 @@ static void dumpObject(ObjectFile &Obj, ScopedPrinter &Writer,
|
|||||||
Dumper->printHashHistograms();
|
Dumper->printHashHistograms();
|
||||||
if (opts::CGProfile)
|
if (opts::CGProfile)
|
||||||
Dumper->printCGProfile();
|
Dumper->printCGProfile();
|
||||||
|
if (opts::BBAddrMap)
|
||||||
|
Dumper->printBBAddrMaps();
|
||||||
if (opts::Addrsig)
|
if (opts::Addrsig)
|
||||||
Dumper->printAddrsig();
|
Dumper->printAddrsig();
|
||||||
if (opts::Notes)
|
if (opts::Notes)
|
||||||
|
@ -482,3 +482,111 @@ Sections:
|
|||||||
DoCheck(0xFFFFFFFF, "can't read an entry at 0x17ffffffe8: it goes past the "
|
DoCheck(0xFFFFFFFF, "can't read an entry at 0x17ffffffe8: it goes past the "
|
||||||
"end of the section (0x18)");
|
"end of the section (0x18)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tests for error paths of the ELFFile::decodeBBAddrMap API.
|
||||||
|
TEST(ELFObjectFileTest, InvalidBBAddrMap) {
|
||||||
|
StringRef CommonYamlString(R"(
|
||||||
|
--- !ELF
|
||||||
|
FileHeader:
|
||||||
|
Class: ELFCLASS64
|
||||||
|
Data: ELFDATA2LSB
|
||||||
|
Type: ET_EXEC
|
||||||
|
Sections:
|
||||||
|
- Name: .llvm_bb_addr_map
|
||||||
|
Type: SHT_LLVM_BB_ADDR_MAP
|
||||||
|
Entries:
|
||||||
|
- Address: 0x11111
|
||||||
|
BBEntries:
|
||||||
|
- AddressOffset: 0x0
|
||||||
|
Size: 0x1
|
||||||
|
Metadata: 0x2
|
||||||
|
)");
|
||||||
|
|
||||||
|
auto DoCheck = [&](StringRef YamlString, const char *ErrMsg) {
|
||||||
|
SmallString<0> Storage;
|
||||||
|
Expected<ELFObjectFile<ELF64LE>> ElfOrErr =
|
||||||
|
toBinary<ELF64LE>(Storage, YamlString);
|
||||||
|
ASSERT_THAT_EXPECTED(ElfOrErr, Succeeded());
|
||||||
|
const ELFFile<ELF64LE> &Elf = ElfOrErr->getELFFile();
|
||||||
|
|
||||||
|
Expected<const typename ELF64LE::Shdr *> BBAddrMapSecOrErr =
|
||||||
|
Elf.getSection(1);
|
||||||
|
ASSERT_THAT_EXPECTED(BBAddrMapSecOrErr, Succeeded());
|
||||||
|
EXPECT_THAT_ERROR(Elf.decodeBBAddrMap(**BBAddrMapSecOrErr).takeError(),
|
||||||
|
FailedWithMessage(ErrMsg));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check that we can detect the malformed encoding when the section is
|
||||||
|
// truncated.
|
||||||
|
SmallString<128> TruncatedYamlString(CommonYamlString);
|
||||||
|
TruncatedYamlString += R"(
|
||||||
|
ShSize: 0x8
|
||||||
|
)";
|
||||||
|
DoCheck(TruncatedYamlString, "unable to decode LEB128 at offset 0x00000008: "
|
||||||
|
"malformed uleb128, extends past end");
|
||||||
|
|
||||||
|
// Check that we can detect when the encoded BB entry fields exceed the UINT32
|
||||||
|
// limit.
|
||||||
|
SmallVector<SmallString<128>, 3> OverInt32LimitYamlStrings(3,
|
||||||
|
CommonYamlString);
|
||||||
|
OverInt32LimitYamlStrings[0] += R"(
|
||||||
|
- AddressOffset: 0x100000000
|
||||||
|
Size: 0xFFFFFFFF
|
||||||
|
Metadata: 0xFFFFFFFF
|
||||||
|
)";
|
||||||
|
|
||||||
|
OverInt32LimitYamlStrings[1] += R"(
|
||||||
|
- AddressOffset: 0xFFFFFFFF
|
||||||
|
Size: 0x100000000
|
||||||
|
Metadata: 0xFFFFFFFF
|
||||||
|
)";
|
||||||
|
|
||||||
|
OverInt32LimitYamlStrings[2] += R"(
|
||||||
|
- AddressOffset: 0xFFFFFFFF
|
||||||
|
Size: 0xFFFFFFFF
|
||||||
|
Metadata: 0x100000000
|
||||||
|
)";
|
||||||
|
|
||||||
|
DoCheck(OverInt32LimitYamlStrings[0],
|
||||||
|
"ULEB128 value at offset 0xc exceeds UINT32_MAX (0x100000000)");
|
||||||
|
DoCheck(OverInt32LimitYamlStrings[1],
|
||||||
|
"ULEB128 value at offset 0x11 exceeds UINT32_MAX (0x100000000)");
|
||||||
|
DoCheck(OverInt32LimitYamlStrings[2],
|
||||||
|
"ULEB128 value at offset 0x16 exceeds UINT32_MAX (0x100000000)");
|
||||||
|
|
||||||
|
// Check the proper error handling when the section has fields exceeding
|
||||||
|
// UINT32 and is also truncated. This is for checking that we don't generate
|
||||||
|
// unhandled errors.
|
||||||
|
SmallVector<SmallString<128>, 3> OverInt32LimitAndTruncated(
|
||||||
|
3, OverInt32LimitYamlStrings[1]);
|
||||||
|
// Truncate before the end of the 5-byte field.
|
||||||
|
OverInt32LimitAndTruncated[0] += R"(
|
||||||
|
ShSize: 0x15
|
||||||
|
)";
|
||||||
|
// Truncate at the end of the 5-byte field.
|
||||||
|
OverInt32LimitAndTruncated[1] += R"(
|
||||||
|
ShSize: 0x16
|
||||||
|
)";
|
||||||
|
// Truncate after the end of the 5-byte field.
|
||||||
|
OverInt32LimitAndTruncated[2] += R"(
|
||||||
|
ShSize: 0x17
|
||||||
|
)";
|
||||||
|
|
||||||
|
DoCheck(OverInt32LimitAndTruncated[0],
|
||||||
|
"unable to decode LEB128 at offset 0x00000011: malformed uleb128, "
|
||||||
|
"extends past end");
|
||||||
|
DoCheck(OverInt32LimitAndTruncated[1],
|
||||||
|
"ULEB128 value at offset 0x11 exceeds UINT32_MAX (0x100000000)");
|
||||||
|
DoCheck(OverInt32LimitAndTruncated[2],
|
||||||
|
"ULEB128 value at offset 0x11 exceeds UINT32_MAX (0x100000000)");
|
||||||
|
|
||||||
|
// Check for proper error handling when the 'NumBlocks' field is overridden
|
||||||
|
// with an out-of-range value.
|
||||||
|
SmallString<128> OverLimitNumBlocks(CommonYamlString);
|
||||||
|
OverLimitNumBlocks += R"(
|
||||||
|
NumBlocks: 0x100000000
|
||||||
|
)";
|
||||||
|
|
||||||
|
DoCheck(OverLimitNumBlocks,
|
||||||
|
"ULEB128 value at offset 0x8 exceeds UINT32_MAX (0x100000000)");
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user