forked from OSchip/llvm-project
[yaml2obj][obj2yaml] - Add a support for SHT_ARM_EXIDX section.
This adds the support for SHT_ARM_EXIDX sections to obj2yaml/yaml2obj tools. SHT_ARM_EXIDX is a ARM specific index table filled with entries. Each entry consists of two 4-bytes values (words). (https://developer.arm.com/documentation/ihi0038/c/?lang=en#index-table-entries) Differential revision: https://reviews.llvm.org/D88228
This commit is contained in:
parent
cabee89bed
commit
dab9917164
|
@ -153,6 +153,7 @@ struct Chunk {
|
|||
StackSizes,
|
||||
SymtabShndxSection,
|
||||
Symver,
|
||||
ARMIndexTable,
|
||||
MipsABIFlags,
|
||||
Addrsig,
|
||||
Fill,
|
||||
|
@ -493,6 +494,23 @@ struct SymtabShndxSection : Section {
|
|||
}
|
||||
};
|
||||
|
||||
struct ARMIndexTableEntry {
|
||||
llvm::yaml::Hex32 Offset;
|
||||
llvm::yaml::Hex32 Value;
|
||||
};
|
||||
|
||||
struct ARMIndexTableSection : Section {
|
||||
Optional<std::vector<ARMIndexTableEntry>> Entries;
|
||||
Optional<yaml::BinaryRef> Content;
|
||||
Optional<llvm::yaml::Hex64> Size;
|
||||
|
||||
ARMIndexTableSection() : Section(ChunkKind::ARMIndexTable) {}
|
||||
|
||||
static bool classof(const Chunk *S) {
|
||||
return S->Kind == ChunkKind::ARMIndexTable;
|
||||
}
|
||||
};
|
||||
|
||||
// Represents .MIPS.abiflags section
|
||||
struct MipsABIFlags : Section {
|
||||
llvm::yaml::Hex16 Version;
|
||||
|
@ -575,6 +593,7 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::VerneedEntry)
|
|||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::Relocation)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::SectionOrType)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::SectionName)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::ARMIndexTableEntry)
|
||||
|
||||
namespace llvm {
|
||||
namespace yaml {
|
||||
|
@ -757,6 +776,10 @@ template <> struct MappingTraits<ELFYAML::Relocation> {
|
|||
static void mapping(IO &IO, ELFYAML::Relocation &Rel);
|
||||
};
|
||||
|
||||
template <> struct MappingTraits<ELFYAML::ARMIndexTableEntry> {
|
||||
static void mapping(IO &IO, ELFYAML::ARMIndexTableEntry &E);
|
||||
};
|
||||
|
||||
template <> struct MappingTraits<std::unique_ptr<ELFYAML::Chunk>> {
|
||||
static void mapping(IO &IO, std::unique_ptr<ELFYAML::Chunk> &C);
|
||||
static StringRef validate(IO &io, std::unique_ptr<ELFYAML::Chunk> &C);
|
||||
|
|
|
@ -259,6 +259,9 @@ template <class ELFT> class ELFState {
|
|||
void writeSectionContent(Elf_Shdr &SHeader,
|
||||
const ELFYAML::VerdefSection &Section,
|
||||
ContiguousBlobAccumulator &CBA);
|
||||
void writeSectionContent(Elf_Shdr &SHeader,
|
||||
const ELFYAML::ARMIndexTableSection &Section,
|
||||
ContiguousBlobAccumulator &CBA);
|
||||
void writeSectionContent(Elf_Shdr &SHeader,
|
||||
const ELFYAML::MipsABIFlags &Section,
|
||||
ContiguousBlobAccumulator &CBA);
|
||||
|
@ -696,6 +699,8 @@ void ELFState<ELFT>::initSectionHeaders(std::vector<Elf_Shdr> &SHeaders,
|
|||
writeSectionContent(SHeader, *S, CBA);
|
||||
} else if (auto S = dyn_cast<ELFYAML::Group>(Sec)) {
|
||||
writeSectionContent(SHeader, *S, CBA);
|
||||
} else if (auto S = dyn_cast<ELFYAML::ARMIndexTableSection>(Sec)) {
|
||||
writeSectionContent(SHeader, *S, CBA);
|
||||
} else if (auto S = dyn_cast<ELFYAML::MipsABIFlags>(Sec)) {
|
||||
writeSectionContent(SHeader, *S, CBA);
|
||||
} else if (auto S = dyn_cast<ELFYAML::NoBitsSection>(Sec)) {
|
||||
|
@ -1514,6 +1519,25 @@ void ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
|
|||
AuxCnt * sizeof(Elf_Vernaux);
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void ELFState<ELFT>::writeSectionContent(
|
||||
Elf_Shdr &SHeader, const ELFYAML::ARMIndexTableSection &Section,
|
||||
ContiguousBlobAccumulator &CBA) {
|
||||
if (Section.Content || Section.Size) {
|
||||
SHeader.sh_size = writeContent(CBA, Section.Content, Section.Size);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Section.Entries)
|
||||
return;
|
||||
|
||||
for (const ELFYAML::ARMIndexTableEntry &E : *Section.Entries) {
|
||||
CBA.write<uint32_t>(E.Offset, ELFT::TargetEndianness);
|
||||
CBA.write<uint32_t>(E.Value, ELFT::TargetEndianness);
|
||||
}
|
||||
SHeader.sh_size = Section.Entries->size() * 8;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
|
||||
const ELFYAML::MipsABIFlags &Section,
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "llvm/ADT/MapVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/BinaryFormat/ELF.h"
|
||||
#include "llvm/Support/ARMEHABI.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/MipsABIFlags.h"
|
||||
|
@ -1267,6 +1268,13 @@ void MappingTraits<ELFYAML::SectionName>::mapping(
|
|||
IO.mapRequired("Section", sectionName.Section);
|
||||
}
|
||||
|
||||
static void sectionMapping(IO &IO, ELFYAML::ARMIndexTableSection &Section) {
|
||||
commonSectionMapping(IO, Section);
|
||||
IO.mapOptional("Content", Section.Content);
|
||||
IO.mapOptional("Size", Section.Size);
|
||||
IO.mapOptional("Entries", Section.Entries);
|
||||
}
|
||||
|
||||
static void sectionMapping(IO &IO, ELFYAML::MipsABIFlags &Section) {
|
||||
commonSectionMapping(IO, Section);
|
||||
IO.mapOptional("Version", Section.Version, Hex16(0));
|
||||
|
@ -1287,6 +1295,12 @@ static void sectionMapping(IO &IO, ELFYAML::MipsABIFlags &Section) {
|
|||
IO.mapOptional("Flags2", Section.Flags2, Hex32(0));
|
||||
}
|
||||
|
||||
static StringRef getStringValue(IO &IO, const char *Key) {
|
||||
StringRef Val;
|
||||
IO.mapRequired(Key, Val);
|
||||
return Val;
|
||||
}
|
||||
|
||||
void MappingTraits<std::unique_ptr<ELFYAML::Chunk>>::mapping(
|
||||
IO &IO, std::unique_ptr<ELFYAML::Chunk> &Section) {
|
||||
ELFYAML::ELF_SHT Type;
|
||||
|
@ -1296,9 +1310,7 @@ void MappingTraits<std::unique_ptr<ELFYAML::Chunk>>::mapping(
|
|||
// When the Type string does not have a "SHT_" prefix, we know it is not a
|
||||
// description of a regular ELF output section. Currently, we have one
|
||||
// special type named "Fill". See comments for Fill.
|
||||
StringRef StrType;
|
||||
IO.mapRequired("Type", StrType);
|
||||
if (StrType == "Fill") {
|
||||
if (getStringValue(IO, "Type") == "Fill") {
|
||||
Section.reset(new ELFYAML::Fill());
|
||||
fillMapping(IO, *cast<ELFYAML::Fill>(Section.get()));
|
||||
return;
|
||||
|
@ -1315,6 +1327,13 @@ void MappingTraits<std::unique_ptr<ELFYAML::Chunk>>::mapping(
|
|||
return;
|
||||
}
|
||||
|
||||
if (Obj.getMachine() == ELF::EM_ARM && Type == ELF::SHT_ARM_EXIDX) {
|
||||
if (!IO.outputting())
|
||||
Section.reset(new ELFYAML::ARMIndexTableSection());
|
||||
sectionMapping(IO, *cast<ELFYAML::ARMIndexTableSection>(Section.get()));
|
||||
return;
|
||||
}
|
||||
|
||||
switch (Type) {
|
||||
case ELF::SHT_DYNAMIC:
|
||||
if (!IO.outputting())
|
||||
|
@ -1580,6 +1599,21 @@ StringRef MappingTraits<std::unique_ptr<ELFYAML::Chunk>>::validate(
|
|||
return {};
|
||||
}
|
||||
|
||||
if (const auto *IT = dyn_cast<ELFYAML::ARMIndexTableSection>(C.get())) {
|
||||
if (IT->Content || IT->Size) {
|
||||
if (IT->Size && IT->Content &&
|
||||
(uint64_t)*IT->Size < IT->Content->binary_size())
|
||||
return "\"Size\" must be greater than or equal to the content "
|
||||
"size";
|
||||
|
||||
if (IT->Entries)
|
||||
return "\"Entries\" cannot be used with \"Content\" or \"Size\"";
|
||||
return {};
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -1692,6 +1726,20 @@ void MappingTraits<ELFYAML::Relocation>::mapping(IO &IO,
|
|||
IO.mapOptional("Addend", Rel.Addend, (ELFYAML::YAMLIntUInt)0);
|
||||
}
|
||||
|
||||
void MappingTraits<ELFYAML::ARMIndexTableEntry>::mapping(
|
||||
IO &IO, ELFYAML::ARMIndexTableEntry &E) {
|
||||
assert(IO.getContext() && "The IO context is not initialized");
|
||||
IO.mapRequired("Offset", E.Offset);
|
||||
|
||||
StringRef CantUnwind = "EXIDX_CANTUNWIND";
|
||||
if (IO.outputting() && (uint32_t)E.Value == ARM::EHABI::EXIDX_CANTUNWIND)
|
||||
IO.mapRequired("Value", CantUnwind);
|
||||
else if (!IO.outputting() && getStringValue(IO, "Value") == CantUnwind)
|
||||
E.Value = ARM::EHABI::EXIDX_CANTUNWIND;
|
||||
else
|
||||
IO.mapRequired("Value", E.Value);
|
||||
}
|
||||
|
||||
void MappingTraits<ELFYAML::Object>::mapping(IO &IO, ELFYAML::Object &Object) {
|
||||
assert(!IO.getContext() && "The IO context is initialized already");
|
||||
IO.setContext(&Object);
|
||||
|
|
|
@ -65,20 +65,19 @@ Sections:
|
|||
- Name: .ARM.exidx
|
||||
Type: SHT_ARM_EXIDX
|
||||
Address: 0x24C
|
||||
ContentArray: [
|
||||
## Entry 1. Address of .ARM.exidx (0x24C) + entry offset (0) + 0x7fffffe4 == 0x230 (func1).
|
||||
0xE4, 0xFF, 0xFF, 0x7F, ## Word(0) = 0x7fffffe4 (31 bit).
|
||||
0xB0, 0xB0, 0xB0, 0x80, ## Word(1): arbitrary opcodes.
|
||||
## Entry 2. Address of .ARM.exidx (0x24C) + entry offset (8) + 0x7fffffe0 == 0x234 (func2).
|
||||
0xE0, 0xFF, 0xFF, 0x7F, ## Word(0) = 0x7fffffe0 (31 bit).
|
||||
0x80, 0x84, 0x9B, 0x80, ## Word(1): arbitrary opcodes.
|
||||
## Entry 3. Address of .ARM.exidx (0x24C) + entry offset (16) + 0x7fffffec == 0x248 (func2).
|
||||
0xEC, 0xFF, 0xFF, 0x7F, ## Word(0) = 0x7fffffec (31 bit).
|
||||
0xB0, 0xB0, 0xB0, 0x80, ## Word(1): arbitrary opcodes.
|
||||
## Entry 4. Address of .ARM.exidx (0x24C) + entry offset (24) + 0x7fffffe8 == 0x24C.
|
||||
0xE8, 0xFF, 0xFF, 0x7F, ## Word(0) = 0x7fffffe8 (31 bit).
|
||||
0x01, 0x00, 0x00, 0x00 ## Word(1) == EXIDX_CANTUNWIND
|
||||
]
|
||||
Entries:
|
||||
## Address of .ARM.exidx (0x24C) + entry offset (0) + 0x7fffffe4 (31 bit) == 0x230 (func1).
|
||||
- Offset: 0x7FFFFFE4
|
||||
Value: 0x80B0B0B0 ## arbitrary opcodes.
|
||||
## Address of .ARM.exidx (0x24C) + entry offset (8) + 0x7fffffe0 (31 bit) == 0x234 (func2).
|
||||
- Offset: 0x7FFFFFE0
|
||||
Value: 0x809B8480 ## arbitrary opcodes.
|
||||
## Address of .ARM.exidx (0x24C) + entry offset (16) + 0x7fffffec (31 bit) == 0x248 (func2).
|
||||
- Offset: 0x7FFFFFEC
|
||||
Value: 0x80B0B0B0 ## arbitrary opcodes.
|
||||
## Address of .ARM.exidx (0x24C) + entry offset (24) + 0x7fffffe8 (31 bit) == 0x24C.
|
||||
- Offset: 0x7FFFFFE8
|
||||
Value: EXIDX_CANTUNWIND
|
||||
Symbols:
|
||||
- Name: func1
|
||||
Type: STT_FUNC
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
## Check how obj2yaml dumps the SHT_ARM_EXIDX section.
|
||||
|
||||
## For a valid section, obj2yaml emits the "Entries" key.
|
||||
## This checks that we respect data endianness and recognize the
|
||||
## EXIDX_CANTUNWIND (0x1) special value properly.
|
||||
|
||||
# RUN: yaml2obj --docnum=1 -DENCODE=LSB %s -o %t.le.so
|
||||
# RUN: obj2yaml %t.le.so | FileCheck %s --check-prefix=LE
|
||||
# RUN: yaml2obj --docnum=1 -DENCODE=MSB %s -o %t.be.so
|
||||
# RUN: obj2yaml %t.be.so | FileCheck %s --check-prefix=BE
|
||||
|
||||
# LE: - Name: .ARM.exidx
|
||||
# LE-NEXT: Type: SHT_ARM_EXIDX
|
||||
# LE-NEXT: Entries:
|
||||
# LE-NEXT: - Offset: 0xDDCCBBAA
|
||||
# LE-NEXT: Value: 0x01000000
|
||||
# LE-NEXT: - Offset: 0x9988FFEE
|
||||
# LE-NEXT: Value: EXIDX_CANTUNWIND
|
||||
# LE-NEXT: ...
|
||||
|
||||
# BE: - Name: .ARM.exidx
|
||||
# BE-NEXT: Type: SHT_ARM_EXIDX
|
||||
# BE-NEXT: Entries:
|
||||
# BE-NEXT: - Offset: 0xAABBCCDD
|
||||
# BE-NEXT: Value: EXIDX_CANTUNWIND
|
||||
# BE-NEXT: - Offset: 0xEEFF8899
|
||||
# BE-NEXT: Value: 0x01000000
|
||||
# BE-NEXT: ...
|
||||
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
Data: ELFDATA2[[ENCODE=LSB]]
|
||||
Type: ET_DYN
|
||||
Machine: EM_ARM
|
||||
Sections:
|
||||
- Name: .ARM.exidx
|
||||
Type: SHT_ARM_EXIDX
|
||||
## 4 words: <arbitrary>, EXIDX_CANTUNWIND in big-endian,
|
||||
## <arbitrary> and EXIDX_CANTUNWIND in little-endian.
|
||||
Content: "AABBCCDD00000001EEFF889901000000"
|
||||
Size: [[SIZE=<none>]]
|
||||
|
||||
## Check that we dump the content of a truncated SHT_ARM_EXIDX section
|
||||
## using the "Content" key.
|
||||
# RUN: yaml2obj --docnum=1 -DSIZE=17 %s -o %t.invalid-size.so
|
||||
# RUN: obj2yaml %t.invalid-size.so | FileCheck %s --check-prefix=INVALID-SIZE
|
||||
|
||||
# INVALID-SIZE: - Name: .ARM.exidx
|
||||
# INVALID-SIZE-NEXT: Type: SHT_ARM_EXIDX
|
||||
# INVALID-SIZE-NEXT: Content: AABBCCDD00000001EEFF88990100000000
|
||||
# INVALID-SIZE-NEXT: ...
|
||||
|
||||
## Check how we dump an empty SHT_ARM_EXIDX section.
|
||||
# RUN: yaml2obj --docnum=2 %s -o %t.empty.so
|
||||
# RUN: obj2yaml %t.empty.so | FileCheck %s --check-prefix=EMPTY
|
||||
|
||||
# EMPTY: - Name: .ARM.exidx
|
||||
# EMPTY-NEXT: Type: SHT_ARM_EXIDX
|
||||
# EMPTY-NEXT: Entries: []
|
||||
# EMPTY-NEXT: ...
|
||||
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_DYN
|
||||
Machine: EM_ARM
|
||||
Sections:
|
||||
- Name: .ARM.exidx
|
||||
Type: SHT_ARM_EXIDX
|
||||
|
||||
## Check how we dump the SHT_ARM_EXIDX (0x70000001) section when
|
||||
## the machine type is not EM_ARM. It is dumped as a regular
|
||||
## section of an unknown type.
|
||||
|
||||
# RUN: yaml2obj --docnum=3 %s -o %t.not-arm.so
|
||||
# RUN: obj2yaml %t.not-arm.so | FileCheck %s --check-prefix=NOT-ARM
|
||||
|
||||
# RUN: yaml2obj --docnum=3 -DMACHINE=EM_ARM %s -o %t.arm.so
|
||||
# RUN: obj2yaml %t.arm.so | FileCheck %s --check-prefix=ARM
|
||||
|
||||
# NOT-ARM: Sections:
|
||||
# NOT-ARM-NEXT: - Name: .ARM.exidx
|
||||
# NOT-ARM-NEXT: Type: 0x70000001
|
||||
# NOT-ARM-NEXT: Content: AABBCCDD11223344
|
||||
# NOT-ARM-NEXT: ...
|
||||
|
||||
# ARM: - Name: .ARM.exidx
|
||||
# ARM-NEXT: Type: SHT_ARM_EXIDX
|
||||
# ARM-NEXT: Entries:
|
||||
# ARM-NEXT: - Offset: 0xDDCCBBAA
|
||||
# ARM-NEXT: Value: 0x44332211
|
||||
# ARM-NEXT: ...
|
||||
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_DYN
|
||||
Machine: [[MACHINE=<none>]]
|
||||
Sections:
|
||||
- Name: .ARM.exidx
|
||||
Type: SHT_PROGBITS
|
||||
ShType: 0x70000001 ## SHT_ARM_EXIDX
|
||||
## An arbitrary valid content.
|
||||
Content: "AABBCCDD11223344"
|
|
@ -0,0 +1,129 @@
|
|||
## Test how we create SHT_ARM_EXIDX sections.
|
||||
|
||||
## Test that the content of SHT_ARM_EXIDX sections,
|
||||
## generated for 32/64-bit little/big endian targets is correct.
|
||||
## Also check that we can use a special EXIDX_CANTUNWIND (0x1) value for a Value field of an entry.
|
||||
# RUN: yaml2obj --docnum=1 -DENCODE=LSB -DCLASS=64 %s -o %t.le64
|
||||
# RUN: llvm-readobj --sections --section-data %t.le64 | FileCheck %s --check-prefixes=DEFAULT,LE
|
||||
# RUN: yaml2obj --docnum=1 -DENCODE=LSB -DCLASS=32 %s -o %t.le32
|
||||
# RUN: llvm-readobj --sections --section-data %t.le32 | FileCheck %s --check-prefixes=DEFAULT,LE
|
||||
# RUN: yaml2obj --docnum=1 -DENCODE=MSB -DCLASS=64 %s -o %t.be64
|
||||
# RUN: llvm-readobj --sections --section-data %t.be64 | FileCheck %s --check-prefixes=DEFAULT,BE
|
||||
# RUN: yaml2obj --docnum=1 -DENCODE=MSB -DCLASS=32 %s -o %t.be32
|
||||
# RUN: llvm-readobj --sections --section-data %t.be32 | FileCheck %s --check-prefixes=DEFAULT,BE
|
||||
|
||||
# DEFAULT: Name: .ARM.exidx (1)
|
||||
# DEFAULT-NEXT: Type: SHT_ARM_EXIDX (0x70000001)
|
||||
# DEFAULT-NEXT: Flags [ (0x0)
|
||||
# DEFAULT-NEXT: ]
|
||||
# DEFAULT-NEXT: Address: 0x0
|
||||
# DEFAULT-NEXT: Offset: 0x{{.*}}
|
||||
# DEFAULT-NEXT: Size: 16
|
||||
# DEFAULT-NEXT: Link: 0
|
||||
# DEFAULT-NEXT: Info: 0
|
||||
# DEFAULT-NEXT: AddressAlignment: 0
|
||||
# DEFAULT-NEXT: EntrySize: 0
|
||||
# DEFAULT-NEXT: SectionData (
|
||||
# LE-NEXT: 0000: DDCCBBAA 44332211 9988FFEE 01000000 |
|
||||
# BE-NEXT: 0000: AABBCCDD 11223344 EEFF8899 00000001 |
|
||||
# DEFAULT-NEXT: )
|
||||
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS[[CLASS=64]]
|
||||
Data: ELFDATA2[[ENCODE=LSB]]
|
||||
Type: ET_DYN
|
||||
Machine: [[MACHINE=EM_ARM]]
|
||||
Sections:
|
||||
- Name: .ARM.exidx
|
||||
Type: SHT_ARM_EXIDX
|
||||
Entries:
|
||||
- Offset: 0xAABBCCDD
|
||||
Value: 0x11223344
|
||||
- Offset: 0xEEFF8899
|
||||
Value: EXIDX_CANTUNWIND
|
||||
|
||||
## Check we only recognize the SHT_ARM_EXIDX section type when machine type is EM_ARM.
|
||||
# RUN: not yaml2obj --docnum=1 -DMACHINE=EM_NONE %s 2>&1 | FileCheck %s --check-prefix=UNKNOWN
|
||||
|
||||
# UNKNOWN: error: invalid hex32 number
|
||||
# UNKNOWN-NEXT: Type: SHT_ARM_EXIDX
|
||||
|
||||
## Check we can set arbitrary section properties for a SHT_ARM_EXIDX section.
|
||||
## Also check that we are able to specify none of "Entries", "Content" nor "Size" keys.
|
||||
|
||||
# RUN: yaml2obj --docnum=2 %s -o %t.props.o
|
||||
# RUN: llvm-readelf --sections %t.props.o | FileCheck %s --check-prefix=PROPERTIES
|
||||
|
||||
# PROPERTIES: [Nr] Name Type Address Off Size ES Flg Lk Inf Al
|
||||
# PROPERTIES: [ 1] .ARM.exidx ARM_EXIDX 0000000000001122 000055 000000 00 AMS 13124 0 85
|
||||
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_REL
|
||||
Machine: EM_ARM
|
||||
Sections:
|
||||
- Name: .ARM.exidx
|
||||
Type: SHT_ARM_EXIDX
|
||||
Flags: [ SHF_ALLOC, SHF_MERGE, SHF_STRINGS ]
|
||||
Address: 0x1122
|
||||
Link: 0x3344
|
||||
AddressAlign: 0x55
|
||||
EntSize: 0x66
|
||||
|
||||
## Check we can't use "Entries" key together with "Content" or "Size" keys.
|
||||
|
||||
# RUN: not yaml2obj --docnum=3 -DSIZE=0 -DENT="[]" %s 2>&1 | \
|
||||
# RUN: FileCheck %s --check-prefix=ENTRIES-ERR
|
||||
# RUN: not yaml2obj --docnum=3 -DCONTENT="'00'" -DENT="[]" %s 2>&1 | \
|
||||
# RUN: FileCheck %s --check-prefix=ENTRIES-ERR
|
||||
|
||||
# ENTRIES-ERR: error: "Entries" cannot be used with "Content" or "Size"
|
||||
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_REL
|
||||
Machine: EM_ARM
|
||||
Sections:
|
||||
- Name: .ARM.exidx
|
||||
Type: SHT_ARM_EXIDX
|
||||
Size: [[SIZE=<none>]]
|
||||
Content: [[CONTENT=<none>]]
|
||||
Entries: [[ENT=<none>]]
|
||||
|
||||
## Check we can use "Content" key with "Size" key when the size is greater
|
||||
## than or equal to the content size.
|
||||
|
||||
# RUN: not yaml2obj --docnum=3 -DCONTENT="'00'" -DSIZE=0 %s 2>&1 | \
|
||||
# RUN: FileCheck %s --check-prefix=CONTENT-SIZE-ERR
|
||||
|
||||
# CONTENT-SIZE-ERR: error: "Size" must be greater than or equal to the content size
|
||||
|
||||
# RUN: yaml2obj --docnum=3 -DCONTENT="'00'" -DSIZE=1 %s -o %t.cont.size.eq.o
|
||||
# RUN: llvm-readobj --sections --section-data %t.cont.size.eq.o | \
|
||||
# RUN: FileCheck %s --check-prefix=CHECK-CONTENT -DDATA="00"
|
||||
|
||||
# RUN: yaml2obj --docnum=3 -DCONTENT="'00'" -DSIZE=2 %s -o %t.cont.size.gr.o
|
||||
# RUN: llvm-readobj --sections --section-data %t.cont.size.gr.o | \
|
||||
# RUN: FileCheck %s --check-prefix=CHECK-CONTENT -DDATA="0000"
|
||||
|
||||
# CHECK-CONTENT: Name: .ARM.exidx
|
||||
# CHECK-CONTENT: SectionData (
|
||||
# CHECK-CONTENT-NEXT: 0000: [[DATA]] |
|
||||
# CHECK-CONTENT-NEXT: )
|
||||
|
||||
## Check we can use "Content" key alone to emit arbitrary content.
|
||||
|
||||
# RUN: yaml2obj --docnum=3 -DCONTENT="'11223344'" %s -o %t.content.o
|
||||
# RUN: llvm-readobj --sections --section-data %t.content.o | \
|
||||
# RUN: FileCheck %s --check-prefix=CHECK-CONTENT -DDATA="11223344"
|
||||
|
||||
## Check we can use "Size" key alone to emit content of an arbitrary size.
|
||||
|
||||
# RUN: yaml2obj --docnum=3 -DSIZE=4 %s -o %t.size.o
|
||||
# RUN: llvm-readobj --sections --section-data %t.size.o | \
|
||||
# RUN: FileCheck %s --check-prefix=CHECK-CONTENT -DDATA="00000000"
|
|
@ -95,6 +95,8 @@ class ELFDumper {
|
|||
Expected<ELFYAML::SymverSection *> dumpSymverSection(const Elf_Shdr *Shdr);
|
||||
Expected<ELFYAML::VerneedSection *> dumpVerneedSection(const Elf_Shdr *Shdr);
|
||||
Expected<ELFYAML::Group *> dumpGroup(const Elf_Shdr *Shdr);
|
||||
Expected<ELFYAML::ARMIndexTableSection *>
|
||||
dumpARMIndexTableSection(const Elf_Shdr *Shdr);
|
||||
Expected<ELFYAML::MipsABIFlags *> dumpMipsABIFlags(const Elf_Shdr *Shdr);
|
||||
Expected<ELFYAML::StackSizesSection *>
|
||||
dumpStackSizesSection(const Elf_Shdr *Shdr);
|
||||
|
@ -460,6 +462,9 @@ ELFDumper<ELFT>::dumpSections() {
|
|||
|
||||
auto GetDumper = [this](unsigned Type)
|
||||
-> std::function<Expected<ELFYAML::Chunk *>(const Elf_Shdr *)> {
|
||||
if (Obj.getHeader().e_machine == ELF::EM_ARM && Type == ELF::SHT_ARM_EXIDX)
|
||||
return [this](const Elf_Shdr *S) { return dumpARMIndexTableSection(S); };
|
||||
|
||||
if (Obj.getHeader().e_machine == ELF::EM_MIPS &&
|
||||
Type == ELF::SHT_MIPS_ABIFLAGS)
|
||||
return [this](const Elf_Shdr *S) { return dumpMipsABIFlags(S); };
|
||||
|
@ -1348,6 +1353,33 @@ Expected<ELFYAML::Group *> ELFDumper<ELFT>::dumpGroup(const Elf_Shdr *Shdr) {
|
|||
return S.release();
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
Expected<ELFYAML::ARMIndexTableSection *>
|
||||
ELFDumper<ELFT>::dumpARMIndexTableSection(const Elf_Shdr *Shdr) {
|
||||
auto S = std::make_unique<ELFYAML::ARMIndexTableSection>();
|
||||
if (Error E = dumpCommonSection(Shdr, *S))
|
||||
return std::move(E);
|
||||
|
||||
Expected<ArrayRef<uint8_t>> ContentOrErr = Obj.getSectionContents(*Shdr);
|
||||
if (!ContentOrErr)
|
||||
return ContentOrErr.takeError();
|
||||
|
||||
if (ContentOrErr->size() % (sizeof(Elf_Word) * 2) != 0) {
|
||||
S->Content = yaml::BinaryRef(*ContentOrErr);
|
||||
return S.release();
|
||||
}
|
||||
|
||||
ArrayRef<Elf_Word> Words(
|
||||
reinterpret_cast<const Elf_Word *>(ContentOrErr->data()),
|
||||
ContentOrErr->size() / sizeof(Elf_Word));
|
||||
|
||||
S->Entries.emplace();
|
||||
for (size_t I = 0, E = Words.size(); I != E; I += 2)
|
||||
S->Entries->push_back({(yaml::Hex32)Words[I], (yaml::Hex32)Words[I + 1]});
|
||||
|
||||
return S.release();
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
Expected<ELFYAML::MipsABIFlags *>
|
||||
ELFDumper<ELFT>::dumpMipsABIFlags(const Elf_Shdr *Shdr) {
|
||||
|
|
Loading…
Reference in New Issue