Skip to content

Commit dab971e

Browse files
authored
[llvm-readobj] Dump SFrame relocations as well (#153161)
If there is a relocation for a particular FDE, print it as well. This is mainly meant for human consumption (otherwise, there's no way to tell which function a given (relocatable) FDE refers to). For testing of relocation generation, I'd still recommend using the regular relocation dumper, as this code will not detect (e.g.) any superfluous relocations. I've considered handling relocations inside the SFrameParser class, but I couldn't find an elegant way to do that. Right now, I don't have a use case for resolving relocations there as lldb (my other use case for SFrameParser) will always operate on linked objects.
1 parent 56681c9 commit dab971e

File tree

4 files changed

+184
-20
lines changed

4 files changed

+184
-20
lines changed

llvm/include/llvm/Object/SFrameParser.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ template <endianness E> class SFrameParser {
4545
// objects returned by the `fdes()` function.
4646
uint64_t getAbsoluteStartAddress(typename FDERange::iterator FDE) const;
4747

48+
// Returns the offset (in the SFrame section) of the given FDE, which must be
49+
// one of the objects returned by the `fdes()` function.
50+
uint64_t offsetOf(typename FDERange::iterator FDE) const;
51+
4852
struct FrameRowEntry {
4953
uint32_t StartAddress;
5054
sframe::FREInfo<endianness::native> Info;

llvm/lib/Object/SFrameParser.cpp

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -98,17 +98,20 @@ uint64_t SFrameParser<E>::getAbsoluteStartAddress(
9898
uint64_t Result = SectionAddress + FDE->StartAddress;
9999

100100
if ((getPreamble().Flags.value() & sframe::Flags::FDEFuncStartPCRel) ==
101-
sframe::Flags::FDEFuncStartPCRel) {
102-
uintptr_t DataPtr = reinterpret_cast<uintptr_t>(Data.data());
103-
uintptr_t FDEPtr = reinterpret_cast<uintptr_t>(&*FDE);
101+
sframe::Flags::FDEFuncStartPCRel)
102+
Result += offsetOf(FDE);
104103

105-
assert(DataPtr <= FDEPtr && FDEPtr < DataPtr + Data.size() &&
106-
"Iterator does not belong to this object!");
104+
return Result;
105+
}
107106

108-
Result += FDEPtr - DataPtr;
109-
}
107+
template <endianness E>
108+
uint64_t SFrameParser<E>::offsetOf(typename FDERange::iterator FDE) const {
109+
uintptr_t DataPtr = reinterpret_cast<uintptr_t>(Data.data());
110+
uintptr_t FDEPtr = reinterpret_cast<uintptr_t>(&*FDE);
110111

111-
return Result;
112+
assert(DataPtr <= FDEPtr && FDEPtr < DataPtr + Data.size() &&
113+
"Iterator does not belong to this object!");
114+
return FDEPtr - DataPtr;
112115
}
113116

114117
template <typename EndianT>
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# RUN: yaml2obj %s -o %t
2+
# RUN: llvm-readobj --sframe %t 2>&1 | \
3+
# RUN: FileCheck %s --strict-whitespace --match-full-lines -DFILE=%t
4+
5+
--- !ELF
6+
FileHeader:
7+
Class: ELFCLASS64
8+
Data: ELFDATA2LSB
9+
Type: ET_REL
10+
Machine: EM_X86_64
11+
Sections:
12+
- Name: .text
13+
Type: SHT_PROGBITS
14+
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
15+
Size: 0x1000
16+
- Name: .sframe
17+
Type: SHT_GNU_SFRAME
18+
Flags: [ SHF_ALLOC ]
19+
ContentArray: [
20+
0xe2, 0xde, 0x02, 0x04, # Preamble (magic, version, flags)
21+
# Header:
22+
0x03, 0x42, 0x40, 0x00, # ABI, Fixed FP offset, Fixed RA Offset, AUX header length
23+
0x03, 0x00, 0x00, 0x00, # Number of FDEs
24+
0x01, 0x00, 0x00, 0x00, # Number of FREs
25+
0x00, 0x10, 0x00, 0x00, # FRE length
26+
0x00, 0x00, 0x00, 0x00, # FDE offset
27+
0x00, 0x00, 0x00, 0x00, # FRE offset
28+
29+
# FDE[0]:
30+
0x00, 0x00, 0xde, 0x00, # Start Address
31+
0xbe, 0x01, 0x00, 0x00, # Size
32+
0x00, 0x00, 0x00, 0x00, # Start FRE Offset
33+
0x01, 0x00, 0x00, 0x00, # Number of FREs
34+
0x00, 0xde, 0xad, 0x00, # Info, RepSize, Padding2
35+
36+
# FDE[1]:
37+
0x00, 0x00, 0xad, 0x00, # Start Address
38+
0xbe, 0x01, 0x00, 0x00, # Size
39+
0x00, 0x00, 0x00, 0x00, # Start FRE Offset
40+
0x00, 0x00, 0x00, 0x00, # Number of FREs
41+
0x00, 0xde, 0xad, 0x00, # Info, RepSize, Padding2
42+
43+
# FDE[2]:
44+
0x00, 0x00, 0xbe, 0x00, # Start Address
45+
0xbe, 0x01, 0x00, 0x00, # Size
46+
0x00, 0x00, 0x00, 0x00, # Start FRE Offset
47+
0x00, 0x00, 0x00, 0x00, # Number of FREs
48+
0x00, 0xde, 0xad, 0x00, # Info, RepSize, Padding2
49+
50+
# FRE[0]:
51+
0x05, 0x02, 0x10, # Start Address, Info, Offset[0]
52+
53+
]
54+
- Name: .rela.sframe
55+
Type: SHT_RELA
56+
Flags: [ SHF_INFO_LINK ]
57+
Link: .symtab
58+
AddressAlign: 0x8
59+
Info: .sframe
60+
Relocations:
61+
- Offset: 0x1c
62+
Symbol: .text
63+
Type: R_X86_64_PC32
64+
Addend: 0x42
65+
- Offset: 0x30
66+
Symbol: .text
67+
Type: R_X86_64_PC32
68+
- Offset: 0x30
69+
Symbol: .text
70+
Type: R_X86_64_PC32
71+
- Offset: 0x44
72+
Symbol: 4747
73+
Type: R_X86_64_PC32
74+
Symbols:
75+
- Name: .text
76+
Type: STT_SECTION
77+
Section: .text
78+
# CHECK-LABEL:SFrame section '.sframe' {
79+
# CHECK: ABI: AMD64EndianLittle (0x3)
80+
# CHECK: FuncDescEntry [0] {
81+
# CHECK-NEXT: PC {
82+
# CHECK-NEXT: Relocation: R_X86_64_PC32
83+
# CHECK-NEXT: Symbol Name: .text
84+
# CHECK-NEXT: Start Address: 0xDE0042
85+
# CHECK-NEXT: }
86+
# CHECK: FREs [
87+
# CHECK-NEXT: Frame Row Entry {
88+
# CHECK-NEXT: Start Address: 0xDE0047
89+
# CHECK: FuncDescEntry [1] {
90+
# CHECK-NEXT:{{.*}}: warning: '[[FILE]]': more than one relocation at offset 0x30
91+
# CHECK-NEXT: PC: 0xAD0030
92+
# CHECK: FuncDescEntry [2] {
93+
# CHECK-NEXT:{{.*}}: warning: '[[FILE]]': unable to read an entry with index 4747 from SHT_SYMTAB section with index {{[0-9]*}}: can't read an entry at 0x{{[0-9a-f]*}}: it goes past the end of the section (0x30)

llvm/tools/llvm-readobj/ELFDumper.cpp

Lines changed: 76 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,13 @@ template <typename ELFT> class ELFDumper : public ObjDumper {
425425
ArrayRef<Elf_Word> getShndxTable(const Elf_Shdr *Symtab) const;
426426

427427
void printSFrameHeader(const SFrameParser<ELFT::Endianness> &Parser);
428-
void printSFrameFDEs(const SFrameParser<ELFT::Endianness> &Parser);
428+
void printSFrameFDEs(const SFrameParser<ELFT::Endianness> &Parser,
429+
ArrayRef<Relocation<ELFT>> Relocations,
430+
const Elf_Shdr *RelocSymTab);
431+
uint64_t getAndPrintSFrameFDEStartAddress(
432+
const SFrameParser<ELFT::Endianness> &Parser,
433+
const typename SFrameParser<ELFT::Endianness>::FDERange::iterator FDE,
434+
ArrayRef<Relocation<ELFT>> Relocations, const Elf_Shdr *RelocSymTab);
429435

430436
private:
431437
mutable SmallVector<std::optional<VersionEntry>, 0> VersionMap;
@@ -6479,15 +6485,16 @@ void ELFDumper<ELFT>::printSFrameHeader(
64796485
if (Expected<ArrayRef<uint8_t>> Aux = Parser.getAuxHeader())
64806486
W.printHexList("Auxiliary header", *Aux);
64816487
else
6482-
reportWarning(Aux.takeError(), FileName);
6488+
reportUniqueWarning(Aux.takeError());
64836489
}
64846490

64856491
template <typename ELFT>
64866492
void ELFDumper<ELFT>::printSFrameFDEs(
6487-
const SFrameParser<ELFT::Endianness> &Parser) {
6493+
const SFrameParser<ELFT::Endianness> &Parser,
6494+
ArrayRef<Relocation<ELFT>> Relocations, const Elf_Shdr *RelocSymTab) {
64886495
typename SFrameParser<ELFT::Endianness>::FDERange FDEs;
64896496
if (Error Err = Parser.fdes().moveInto(FDEs)) {
6490-
reportWarning(std::move(Err), FileName);
6497+
reportUniqueWarning(std::move(Err));
64916498
return;
64926499
}
64936500

@@ -6497,8 +6504,8 @@ void ELFDumper<ELFT>::printSFrameFDEs(
64976504
W,
64986505
formatv("FuncDescEntry [{0}]", std::distance(FDEs.begin(), It)).str());
64996506

6500-
uint64_t FDEStartAddress = Parser.getAbsoluteStartAddress(It);
6501-
W.printHex("PC", FDEStartAddress);
6507+
uint64_t FDEStartAddress =
6508+
getAndPrintSFrameFDEStartAddress(Parser, It, Relocations, RelocSymTab);
65026509
W.printHex("Size", It->Size);
65036510
W.printHex("Start FRE Offset", It->StartFREOff);
65046511
W.printNumber("Num FREs", It->NumFREs);
@@ -6553,13 +6560,49 @@ void ELFDumper<ELFT>::printSFrameFDEs(
65536560
W.printList("Extra Offsets", Offs);
65546561
}
65556562
if (Err)
6556-
reportWarning(std::move(Err), FileName);
6563+
reportUniqueWarning(std::move(Err));
6564+
}
6565+
}
6566+
6567+
template <typename ELFT>
6568+
uint64_t ELFDumper<ELFT>::getAndPrintSFrameFDEStartAddress(
6569+
const SFrameParser<ELFT::Endianness> &Parser,
6570+
const typename SFrameParser<ELFT::Endianness>::FDERange::iterator FDE,
6571+
ArrayRef<Relocation<ELFT>> Relocations, const Elf_Shdr *RelocSymTab) {
6572+
uint64_t Address = Parser.getAbsoluteStartAddress(FDE);
6573+
uint64_t Offset = Parser.offsetOf(FDE);
6574+
6575+
auto Reloc = llvm::lower_bound(
6576+
Relocations, Offset, [](auto R, uint64_t O) { return R.Offset < O; });
6577+
if (Reloc == Relocations.end() || Reloc->Offset != Offset) {
6578+
W.printHex("PC", Address);
6579+
} else if (std::next(Reloc) != Relocations.end() &&
6580+
std::next(Reloc)->Offset == Offset) {
6581+
reportUniqueWarning(
6582+
formatv("more than one relocation at offset {0:x+}", Offset));
6583+
W.printHex("PC", Address);
6584+
} else if (Expected<RelSymbol<ELFT>> RelSym =
6585+
getRelocationTarget(*Reloc, RelocSymTab);
6586+
!RelSym) {
6587+
reportUniqueWarning(RelSym.takeError());
6588+
W.printHex("PC", Address);
6589+
} else {
6590+
// Exactly one relocation at the given offset. Print it.
6591+
DictScope PCScope(W, "PC");
6592+
SmallString<32> RelocName;
6593+
Obj.getRelocationTypeName(Reloc->Type, RelocName);
6594+
W.printString("Relocation", RelocName);
6595+
W.printString("Symbol Name", RelSym->Name);
6596+
Address = FDE->StartAddress + Reloc->Addend.value_or(0);
6597+
W.printHex("Start Address", Address);
65576598
}
6599+
return Address;
65586600
}
65596601

65606602
template <typename ELFT>
65616603
void ELFDumper<ELFT>::printSectionsAsSFrame(ArrayRef<std::string> Sections) {
65626604
constexpr endianness E = ELFT::Endianness;
6605+
65636606
for (object::SectionRef Section :
65646607
getSectionRefsByNameOrIndex(ObjF, Sections)) {
65656608
// Validity of sections names checked in getSectionRefsByNameOrIndex.
@@ -6570,21 +6613,42 @@ void ELFDumper<ELFT>::printSectionsAsSFrame(ArrayRef<std::string> Sections) {
65706613

65716614
StringRef SectionContent;
65726615
if (Error Err = Section.getContents().moveInto(SectionContent)) {
6573-
reportWarning(std::move(Err), FileName);
6616+
reportUniqueWarning(std::move(Err));
65746617
continue;
65756618
}
65766619

65776620
Expected<object::SFrameParser<E>> Parser = object::SFrameParser<E>::create(
65786621
arrayRefFromStringRef(SectionContent), Section.getAddress());
65796622
if (!Parser) {
6580-
reportWarning(createError("invalid sframe section: " +
6581-
toString(Parser.takeError())),
6582-
FileName);
6623+
reportUniqueWarning("invalid sframe section: " +
6624+
toString(Parser.takeError()));
65836625
continue;
65846626
}
65856627

6628+
const Elf_Shdr *ELFSection = ObjF.getSection(Section.getRawDataRefImpl());
6629+
MapVector<const Elf_Shdr *, const Elf_Shdr *> RelocationMap;
6630+
if (Error Err = Obj.getSectionAndRelocations(
6631+
[&](const Elf_Shdr &S) { return &S == ELFSection; })
6632+
.moveInto(RelocationMap)) {
6633+
reportUniqueWarning(std::move(Err));
6634+
}
6635+
6636+
std::vector<Relocation<ELFT>> Relocations;
6637+
const Elf_Shdr *RelocSymTab = nullptr;
6638+
if (const Elf_Shdr *RelocSection = RelocationMap.lookup(ELFSection)) {
6639+
forEachRelocationDo(*RelocSection,
6640+
[&](const Relocation<ELFT> &R, unsigned Ndx,
6641+
const Elf_Shdr &Sec, const Elf_Shdr *SymTab) {
6642+
RelocSymTab = SymTab;
6643+
Relocations.push_back(R);
6644+
});
6645+
llvm::stable_sort(Relocations, [](const auto &LHS, const auto &RHS) {
6646+
return LHS.Offset < RHS.Offset;
6647+
});
6648+
}
6649+
65866650
printSFrameHeader(*Parser);
6587-
printSFrameFDEs(*Parser);
6651+
printSFrameFDEs(*Parser, Relocations, RelocSymTab);
65886652
}
65896653
}
65906654

0 commit comments

Comments
 (0)