forked from OSchip/llvm-project
[ifs] Allow llvm-ifs to generate text stub from elf stub
ELF stubs generated from llvm-ifs lacks program headers, which prevents llvm-ifs from parsing them properly as program headers are required by llvm's own ELF libraries. This patch adds a few workaround bypass this limitation. Differential Revision: https://reviews.llvm.org/D116769
This commit is contained in:
parent
a59bb21bf8
commit
15dfe03022
|
@ -335,6 +335,89 @@ private:
|
|||
write(Data + shdrOffset(Sec), Sec.Shdr);
|
||||
}
|
||||
};
|
||||
|
||||
/// This function takes an error, and appends a string of text to the end of
|
||||
/// that error. Since "appending" to an Error isn't supported behavior of an
|
||||
/// Error, this function technically creates a new error with the combined
|
||||
/// message and consumes the old error.
|
||||
///
|
||||
/// @param Err Source error.
|
||||
/// @param After Text to append at the end of Err's error message.
|
||||
Error appendToError(Error Err, StringRef After) {
|
||||
std::string Message;
|
||||
raw_string_ostream Stream(Message);
|
||||
Stream << Err;
|
||||
Stream << " " << After;
|
||||
consumeError(std::move(Err));
|
||||
return createError(Stream.str());
|
||||
}
|
||||
|
||||
template <class ELFT> class DynSym {
|
||||
using Elf_Shdr_Range = typename ELFT::ShdrRange;
|
||||
using Elf_Shdr = typename ELFT::Shdr;
|
||||
|
||||
public:
|
||||
static Expected<DynSym> create(const ELFFile<ELFT> &ElfFile,
|
||||
const DynamicEntries &DynEnt) {
|
||||
Expected<Elf_Shdr_Range> Shdrs = ElfFile.sections();
|
||||
if (!Shdrs)
|
||||
return Shdrs.takeError();
|
||||
return DynSym(ElfFile, DynEnt, *Shdrs);
|
||||
}
|
||||
|
||||
Expected<const uint8_t *> getDynSym() {
|
||||
if (DynSymHdr)
|
||||
return ElfFile.base() + DynSymHdr->sh_offset;
|
||||
return getDynamicData(DynEnt.DynSymAddr, "dynamic symbol table");
|
||||
}
|
||||
|
||||
Expected<StringRef> getDynStr() {
|
||||
if (DynSymHdr)
|
||||
return ElfFile.getStringTableForSymtab(*DynSymHdr, Shdrs);
|
||||
Expected<const uint8_t *> DataOrErr = getDynamicData(
|
||||
DynEnt.StrTabAddr, "dynamic string table", DynEnt.StrSize);
|
||||
if (!DataOrErr)
|
||||
return DataOrErr.takeError();
|
||||
return StringRef(reinterpret_cast<const char *>(*DataOrErr),
|
||||
DynEnt.StrSize);
|
||||
}
|
||||
|
||||
private:
|
||||
DynSym(const ELFFile<ELFT> &ElfFile, const DynamicEntries &DynEnt,
|
||||
Elf_Shdr_Range Shdrs)
|
||||
: ElfFile(ElfFile), DynEnt(DynEnt), Shdrs(Shdrs),
|
||||
DynSymHdr(findDynSymHdr()) {}
|
||||
|
||||
const Elf_Shdr *findDynSymHdr() {
|
||||
for (const Elf_Shdr &Sec : Shdrs)
|
||||
if (Sec.sh_type == SHT_DYNSYM) {
|
||||
// If multiple .dynsym are present, use the first one.
|
||||
// This behavior aligns with llvm::object::ELFFile::getDynSymtabSize()
|
||||
return &Sec;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Expected<const uint8_t *> getDynamicData(uint64_t EntAddr, StringRef Name,
|
||||
uint64_t Size = 0) {
|
||||
Expected<const uint8_t *> SecPtr = ElfFile.toMappedAddr(EntAddr);
|
||||
if (!SecPtr)
|
||||
return appendToError(
|
||||
SecPtr.takeError(),
|
||||
("when locating " + Name + " section contents").str());
|
||||
Expected<const uint8_t *> SecEndPtr = ElfFile.toMappedAddr(EntAddr + Size);
|
||||
if (!SecEndPtr)
|
||||
return appendToError(
|
||||
SecEndPtr.takeError(),
|
||||
("when locating " + Name + " section contents").str());
|
||||
return *SecPtr;
|
||||
}
|
||||
|
||||
const ELFFile<ELFT> &ElfFile;
|
||||
const DynamicEntries &DynEnt;
|
||||
Elf_Shdr_Range Shdrs;
|
||||
const Elf_Shdr *DynSymHdr;
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
/// This function behaves similarly to StringRef::substr(), but attempts to
|
||||
|
@ -354,22 +437,6 @@ static Expected<StringRef> terminatedSubstr(StringRef Str, size_t Offset) {
|
|||
return Str.substr(Offset, StrLen);
|
||||
}
|
||||
|
||||
/// This function takes an error, and appends a string of text to the end of
|
||||
/// that error. Since "appending" to an Error isn't supported behavior of an
|
||||
/// Error, this function technically creates a new error with the combined
|
||||
/// message and consumes the old error.
|
||||
///
|
||||
/// @param Err Source error.
|
||||
/// @param After Text to append at the end of Err's error message.
|
||||
Error appendToError(Error Err, StringRef After) {
|
||||
std::string Message;
|
||||
raw_string_ostream Stream(Message);
|
||||
Stream << Err;
|
||||
Stream << " " << After;
|
||||
consumeError(std::move(Err));
|
||||
return createError(Stream.str());
|
||||
}
|
||||
|
||||
/// This function populates a DynamicEntries struct using an ELFT::DynRange.
|
||||
/// After populating the struct, the members are validated with
|
||||
/// some basic correctness checks.
|
||||
|
@ -508,7 +575,6 @@ template <class ELFT>
|
|||
static Expected<std::unique_ptr<IFSStub>>
|
||||
buildStub(const ELFObjectFile<ELFT> &ElfObj) {
|
||||
using Elf_Dyn_Range = typename ELFT::DynRange;
|
||||
using Elf_Phdr_Range = typename ELFT::PhdrRange;
|
||||
using Elf_Sym_Range = typename ELFT::SymRange;
|
||||
using Elf_Sym = typename ELFT::Sym;
|
||||
std::unique_ptr<IFSStub> DestStub = std::make_unique<IFSStub>();
|
||||
|
@ -519,25 +585,19 @@ buildStub(const ELFObjectFile<ELFT> &ElfObj) {
|
|||
return DynTable.takeError();
|
||||
}
|
||||
|
||||
// Fetch program headers.
|
||||
Expected<Elf_Phdr_Range> PHdrs = ElfFile.program_headers();
|
||||
if (!PHdrs) {
|
||||
return PHdrs.takeError();
|
||||
}
|
||||
|
||||
// Collect relevant .dynamic entries.
|
||||
DynamicEntries DynEnt;
|
||||
if (Error Err = populateDynamic<ELFT>(DynEnt, *DynTable))
|
||||
return std::move(Err);
|
||||
Expected<DynSym<ELFT>> EDynSym = DynSym<ELFT>::create(ElfFile, DynEnt);
|
||||
if (!EDynSym)
|
||||
return EDynSym.takeError();
|
||||
|
||||
// Get pointer to in-memory location of .dynstr section.
|
||||
Expected<const uint8_t *> DynStrPtr = ElfFile.toMappedAddr(DynEnt.StrTabAddr);
|
||||
if (!DynStrPtr)
|
||||
return appendToError(DynStrPtr.takeError(),
|
||||
"when locating .dynstr section contents");
|
||||
Expected<StringRef> EDynStr = EDynSym->getDynStr();
|
||||
if (!EDynStr)
|
||||
return EDynStr.takeError();
|
||||
|
||||
StringRef DynStr(reinterpret_cast<const char *>(DynStrPtr.get()),
|
||||
DynEnt.StrSize);
|
||||
StringRef DynStr = *EDynStr;
|
||||
|
||||
// Populate Arch from ELF header.
|
||||
DestStub->Target.Arch = static_cast<IFSArch>(ElfFile.getHeader().e_machine);
|
||||
|
@ -573,8 +633,7 @@ buildStub(const ELFObjectFile<ELFT> &ElfObj) {
|
|||
return SymCount.takeError();
|
||||
if (*SymCount > 0) {
|
||||
// Get pointer to in-memory location of .dynsym section.
|
||||
Expected<const uint8_t *> DynSymPtr =
|
||||
ElfFile.toMappedAddr(DynEnt.DynSymAddr);
|
||||
Expected<const uint8_t *> DynSymPtr = EDynSym->getDynSym();
|
||||
if (!DynSymPtr)
|
||||
return appendToError(DynSymPtr.takeError(),
|
||||
"when locating .dynsym section contents");
|
||||
|
|
|
@ -44,4 +44,4 @@ ProgramHeaders:
|
|||
FirstSec: .dynamic
|
||||
LastSec: .dynamic
|
||||
|
||||
# CHECK: virtual address is not in any segment: 0x260 when locating .dynstr section contents
|
||||
# CHECK: virtual address is not in any segment: 0x260 when locating dynamic string table section contents
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
## Test writing stub ELF from IFS and read stub ELF to regenerate IFS.
|
||||
|
||||
# RUN: llvm-ifs --output-elf=%t.elf64l --arch=x86_64 --bitwidth=64 --endianness=little %s
|
||||
# RUN: llvm-ifs --output-ifs=- --strip-ifs-target %t.elf64l | FileCheck %s
|
||||
|
||||
--- !ifs-v1
|
||||
IfsVersion: 3.0
|
||||
NeededLibs:
|
||||
- libc.so.6
|
||||
Symbols:
|
||||
- { Name: bar, Type: Object, Size: 42 }
|
||||
- { Name: baz, Type: TLS, Size: 3 }
|
||||
- { Name: plus, Type: Func }
|
||||
...
|
||||
|
||||
# CHECK: --- !ifs-v1
|
||||
# CHECK-NEXT: IfsVersion: 3.0
|
||||
# CHECK-NEXT: NeededLibs:
|
||||
# CHECK-NEXT: - libc.so.6
|
||||
# CHECK-NEXT: Symbols:
|
||||
# CHECK-NEXT: - { Name: bar, Type: Object, Size: 42 }
|
||||
# CHECK-NEXT: - { Name: baz, Type: TLS, Size: 3 }
|
||||
# CHECK-NEXT: - { Name: plus, Type: Func }
|
||||
# CHECK-NEXT: ...
|
Loading…
Reference in New Issue