Index: llvm/tools/llvm-objcopy/MutableObject/MutableObject.h =================================================================== --- /dev/null +++ llvm/tools/llvm-objcopy/MutableObject/MutableObject.h @@ -0,0 +1,154 @@ +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Object/ELF.h" +#include "llvm/Object/ELFObjectFile.h" +#include "llvm/Object/ELFTypes.h" +#define protected public +#include "llvm/Object/ObjectFile.h" +#undef protected +#include "llvm/Support/Errc.h" +#include "llvm/Support/Error.h" +#include +#include +#include + +using namespace llvm; +using namespace object; + +template class MutableELFObject; + +class SectionBase { +protected: + ArrayRef Data; + StringRef Name; + +public: + SectionBase() = default; + SectionBase(const SectionBase &) = default; + SectionBase(SectionBase &&) = default; + SectionBase(ArrayRef Data, StringRef Name) : Data(Data), Name(Name) {} + virtual ~SectionBase() {} + + StringRef name() const { return Name; } + + virtual SectionBase *clone(Optional NewName = None) const { + auto Ptr = new SectionBase(*this); + if (NewName) + Ptr->Name = *NewName; + return Ptr; + } +}; + +class MutableObject { +// Access modifiers are pretty permissive throughout for now because +// I can't be bothered to make getters. +protected: + using SecPtr = std::unique_ptr; + using key_t = uint64_t; + + std::unordered_map UpdatedSections; + + std::vector Sections; + + class section_range {}; + +public: + MutableObject() = default; + MutableObject(const MutableObject &) = default; + MutableObject(MutableObject &&) = default; + virtual ~MutableObject() {} + virtual Error init() = 0; + + virtual const uint8_t *base() const = 0; + + Error renameSection(uint64_t Index, StringRef NewName) { + if (Index > Sections.size()) + return createError("section doesn't exist"); + UpdatedSections[Index] = + std::unique_ptr(Sections[Index]->clone(NewName)); + return Error::success(); + } + + Optional getSection(uint64_t Index) const { + // Searching if the key exists so is_contained doesn't work. + auto Found = UpdatedSections.find(Index); + if (Found != UpdatedSections.end()) { + if (Found->second.get()) + return Found->second.get(); + return None; + } + if (Index > Sections.size()) return None; + return Sections[Index].get(); + } + + section_range sections() const; +}; + +template +class ELFSection : public SectionBase { + const Elf_Shdr_Base &Shdr; + +public: + ELFSection(const Elf_Shdr_Base &Shdr, MutableELFObject &Object) + : SectionBase(ArrayRef(Object.base() + Shdr.sh_offset, Shdr.sh_size), + Object.nameFromShstrtab(Shdr.sh_name)), Shdr(Shdr) {} + + ELFSection(const ELFSection &) = default; + ELFSection(ELFSection &&) = default; + + ELFSection *clone(Optional NewName = None) const override { + auto Ptr = new ELFSection(*this); + if (NewName) + Ptr->Name = *NewName; + return Ptr; + } +}; + +template +class MutableELFObject : public MutableObject { + ELFObjectFile &Object; + ArrayRef Shstrtab; + +public: + MutableELFObject(ELFObjectFile &Object) : Object(Object) {} + + Error init() override; + + const uint8_t *base() const override { + return Object.base(); + } + + static StringRef nameFromStrtab(uint64_t Index, ArrayRef Strtab) { + if (!Strtab.data()) + return StringRef(); + + assert(Index < Strtab.size()); + return reinterpret_cast(Strtab.data()) + Index; + } + + StringRef nameFromShstrtab(uint64_t Index) const { return nameFromStrtab(Index, Shstrtab); } +}; + +template +Error MutableELFObject::init() { + auto &Header = *Object.getELFFile()->getHeader(); + auto SectionsOrErr = Object.getELFFile()->sections(); + if (!SectionsOrErr) + return SectionsOrErr.takeError(); + auto SectionArr = SectionsOrErr.get(); + Shstrtab = ArrayRef(base() + SectionArr[Header.e_shstrndx].sh_offset, + SectionArr[Header.e_shstrndx].sh_size); + + Sections.reserve(Header.e_shnum); + for (const auto &Shdr : SectionArr) { + // Later construct different classes derived from ELF section but + // for now just create an ELFSection. + switch (Shdr.sh_type) { + default: + Sections.emplace_back(make_unique>(Shdr, *this)); + } + } + + return Error::success(); +} Index: llvm/tools/llvm-objcopy/llvm-objcopy.cpp =================================================================== --- llvm/tools/llvm-objcopy/llvm-objcopy.cpp +++ llvm/tools/llvm-objcopy/llvm-objcopy.cpp @@ -46,6 +46,8 @@ #include #include +#include "MutableObject/MutableObject.h" + namespace llvm { namespace objcopy { @@ -209,7 +211,7 @@ if (Config.PreserveDates) if (auto EC = sys::fs::status(Config.InputFilename, Stat)) return createFileError(Config.InputFilename, EC); - + if (Config.InputFormat == "binary") { auto BufOrErr = MemoryBuffer::getFile(Config.InputFilename); if (!BufOrErr) @@ -245,9 +247,48 @@ return Error::success(); } +static Error testing(StringRef Filename) { + Expected> BinaryOrErr = + object::createBinary(Filename); + if (!BinaryOrErr) + return createFileError(Filename, BinaryOrErr.takeError()); + + auto *ELFBinary = dyn_cast>(BinaryOrErr->getBinary()); + if (!ELFBinary) + return createError("not an ELF file"); + + auto MutObject = MutableELFObject(*ELFBinary); + if (Error E = MutObject.init()) + return E; + + outs() << MutObject.nameFromShstrtab(1) << "\n"; + + auto Sec = MutObject.getSection(1).getValue()->name(); + outs() << Sec << "\n"; + + if (Error E = MutObject.renameSection(1, ".sec.new")) + return E; + + auto NewSec = MutObject.getSection(1).getValue()->name(); + outs() << NewSec << "\n"; + + assert(NewSec != Sec); + assert(NewSec == ".sec.new"); + + return Error::success(); +} + int main(int argc, char **argv) { InitLLVM X(argc, argv); ToolName = argv[0]; + if (!strcmp(argv[1], "TEST")) { + if (Error E = testing(argv[2])) { + logAllUnhandledErrors(std::move(E), WithColor::error(errs(), ToolName)); + return 1; + } + return 0; + } + bool IsStrip = sys::path::stem(ToolName).contains("strip"); Expected DriverConfig = IsStrip ? parseStripOptions(makeArrayRef(argv + 1, argc))