Index: llvm/include/llvm/Object/MutableELFObject.h =================================================================== --- /dev/null +++ llvm/include/llvm/Object/MutableELFObject.h @@ -0,0 +1,80 @@ +#ifndef LLVM_OBJECT_MUTABLEELFOBJECT_H +#define LLVM_OBJECT_MUTABLEELFOBJECT_H + +#include "MutableObject.h" +#include "ELFTypes.h" +#include "ELFObjectFile.h" + +namespace llvm { +namespace object { +namespace mutable_object { + +template +class ELFSection : public SectionBase { + Elf_Shdr_Base SectionHeader; + +public: + ELFSection(const ELFSection &) = default; + ELFSection(ELFSection &&) = default; + ELFSection(const MutableObject &OwningObject, + ArrayRef Data, StringRef Name, Elf_Shdr_Base &Shdr) + : SectionBase(OwningObject, Data, Name), SectionHeader(Shdr) {} + + ~ELFSection() override {} + + + static bool classof(const SectionBase *Sec) { + return isa(Sec->getOwningObject()); + } + + std::unique_ptr clone() const override { + return make_unique(*this); + } +}; + +template +class ELFSegment : public SegmentBase { + Elf_Phdr_Impl ProgramHeader; +}; + +template +class MutableELFObject : public MutableObject { + Elf_Ehdr_Impl Header; + + const ELFObjectFile &getObjectFile() const override { + auto *Ret = dyn_cast>(ObjFile); + assert(Ret); + return *Ret; + } + + MutableELFObject(const ObjectFile &ObjFile) : MutableObject(ObjFile) {} +public: + static Expected> + create(const ObjectFile &ObjFile) { + MutableELFObject Object(ObjFile); + auto ELFObjFile = Object.getObjectFile(); + Object.Header = ELFObjFile.getHeader(); + auto *Base = ELFObjFile.getData().data(); + + ArrayRef> SectionHeaders(Base + Object.Header.e_shoff, + Object.Header.e_shnum); + auto *Shstrtab = Base + Object.Header.e_shstrndx; + std::vector> OriginalSections; + for (const auto &Shdr : SectionHeaders) { + OriginalSections.push_back(make_unique( + Object, ArrayRef(Shdr.sh_offset, Shdr.sh_size), + Shstrtab + Shdr.sh_name, Shdr)); + } + + Object.Sections = SectionList(std::move(OriginalSections)); + + return std::unique_ptr(Object); + } + +}; + +} // namespace mutable_object +} // namespace object +} // namespace llvm + +#endif // LLVM_OBJECT_MUTABLEELFOBJECT_H Index: llvm/include/llvm/Object/MutableObject.h =================================================================== --- /dev/null +++ llvm/include/llvm/Object/MutableObject.h @@ -0,0 +1,280 @@ + +#ifndef LLVM_OBJECT_MUTABLEOBJECT_H +#define LLVM_OBJECT_MUTABLEOBJECT_H + +#include "ObjectFile.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/Errc.h" +#include +#include +#include +#include + +namespace llvm { +namespace object { +namespace mutable_object { + +class MutableObject; +class SectionBase; +class SegmentBase; + +struct alignas(8) DataRef { + uint64_t Index : 63; + bool New : 1; + + DataRef() : Index(0), New(false) {} + DataRef(uint64_t Index) : Index(Index), New(true) {} + DataRef(uint64_t Index, bool Updated) : Index(Index), New(Updated) {} + + operator unsigned long() const { return Index; } + DataRef operator++() { return ++Index; } + + bool operator==(const DataRef &Other) { + return Other.Index == Index && Other.New == New; + } + + bool operator<(const DataRef &Rhs) { + if (New == Rhs.New) + return Index < Rhs.Index; + return New < Rhs.New; + } +}; + +template +class UpdatableList { + template + friend class MutableObjectRange; + + using Ptr = std::unique_ptr; + + // Should be formally made by MutableObject::init. + // MutableObject::Mutableobject uses the default constructor so + // use this to ensure that no member functions are called unless + // it has been properly made with UpdatableList(const ArrayRef). + bool Made = false; + + const std::vector Original; + std::map Updated; + +public: + UpdatableList() = default; + UpdatableList(const std::vector &&Original) : Made(true), Original(Original) {} + + const Entity &operator[](uint64_t Index) const { + assert(Made && "Invalid object"); + auto Found = Updated.find(Index); + if (Found != Updated.end()) { + assert(Found->second.get() && "nullptr in updated map"); + return *Found->second.get(); + } + return *Original[Index].get(); + } + + /// Original sections are immutable, return them as const + /// this is the same as operator[](uint64_t) for original indexes. + const Entity &getOriginal(uint64_t Index) const { + assert(Index < Original.size() && "Out of range"); + return *Original[Index].get(); + } + + /// Sections that have been updated should not be immutable + /// so return them as non const. + Entity &getNew(uint64_t Index) { + auto Found = Updated.find(Index); + if (Found == Updated.end()) { + const Entity &Original = getOriginal(Index); + Updated[Index] = Original.clone(); + return *Updated.find(Index)->second; + } + return *Found->second.get(); + } + + Error remove(DataRef Index) { + assert(Made && "Invalid object"); + if (Index.New) { + auto Found = Updated.find(Index); + if (Found == Updated.end()) + return createStringError(errc::argument_out_of_domain, + "Removing updated section that doesn't exist"); + } else { + assert(Index.Index < Original.size() && "Out of range"); + } + Updated[Index] = nullptr; + return Error::success(); + } + + Error update(DataRef Index, Ptr New) { + assert(Made && "Invalid object"); + if (Index.New) { + auto Found = Updated.find(Index); + if (Found == Updated.end()) + return createStringError(errc::argument_out_of_domain, + "Updating section that doesn't exist"); + } else { + assert(Index.Index < Original.size() && "Out of range"); + } + Updated[Index] = std::move(New); + return Error::success(); + } +}; + +template +class MutableObjectRange { + friend class MutableObject; + UpdatableList &List; + + using reference = Iterable&; + using pointer = Iterable*; + +public: + MutableObjectRange(UpdatableList &List); + + // template + class Iter { + friend class MutableObjectRange; + + UpdatableList &List; + + DataRef Index = UINT64_MAX; + pointer Current = nullptr; + + Iter(UpdatableList &List) : List(List) { + operator++(); + } + + static Iter createEnd(UpdatableList &List) { + Iter Ret(List); + Ret.Index = DataRef(List.Original.size(), false); + Ret.Current = nullptr; + return Ret; + } + + public: + Iter operator++() { + const auto End = List.Updated.end(); + for (;;) { + ++Index; + auto Found = List.Updated.find(Index); + if (Found != End) { + // nullptr in UpdatedSections means it was removed, skip it. + if (!Found->second.get()) + continue; + + Index.New = true; + Current = Found->second.get(); + return *this; + } + + Index.New = false; + if (Index >= List.Original.size()) { + assert(Index.Index == List.Original.size() && "Should not have gone past"); + Index.Index = List.Original.size(); + Current = nullptr; + return *this; + } + + Current = List.Original[Index].get(); + return *this; + } + llvm_unreachable("impossible to exit loop without returning"); + } + + const pointer operator->() const { return Current; } + reference operator*() const { + assert(Current && "Current was nullptr"); + return *Current; + } + + bool operator==(const Iter &Other) const { + return Other.Current == Current; + } + + bool operator!=(const Iter &Other) const { + return !operator==(Other); + } + + DataRef getCurrentDataRef() const { + return Index; + } + }; + + Iter begin() { return Iter(List); } + Iter end() { return Iter::createEnd(List); } +}; + +class SectionBase { + const MutableObject &OwningObject; + const SegmentBase *OwnedSegment = nullptr; + ArrayRef Data; + StringRef Name; + +public: + SectionBase(const SectionBase &) = default; + SectionBase(SectionBase &&) = default; + SectionBase(const MutableObject &OwningObject, + ArrayRef Data, StringRef Name); + virtual ~SectionBase(); + + StringRef name() const; + ArrayRef data() const; + const MutableObject &getOwningObject() const; + + virtual std::unique_ptr clone() const; +}; + +class SegmentBase { + const MutableObject &OwningObject; + std::set Sections; + +public: + SegmentBase(const MutableObject &OwningObject); + virtual ~SegmentBase(); + + virtual std::unique_ptr clone() const; + + void removeSection(uint64_t Section); + void addSection(uint64_t Section); +}; + +using SectionList = UpdatableList; +using SegmentList = UpdatableList; + +class MutableObject { +protected: + const ObjectFile &ObjFile; + + SectionList Sections; + SegmentList Segments; + + virtual const ObjectFile &getObjectFile() const; + + MutableObject(const ObjectFile &ObjFile); +public: + virtual ~MutableObject(); + + static Expected> + createMutableObject(const ObjectFile &ObjFile); + + virtual Error init() = 0; + + virtual void finalize(); + + Optional findSectionByName(StringRef Name) const; + Error removeSection(DataRef Section); + Error replaceSection(DataRef ToReplace, std::unique_ptr New); + + MutableObjectRange sections() const; + MutableObjectRange segments() const; + + /// Creates a new section if Section is larger than the number of sections, + /// or returns a mutable copy of a current section. + SectionBase &getMutableSection(DataRef Section); + + SegmentBase &getMutableSegment(DataRef Segment); +}; + +} // namespace mutable_object +} // namespace object +} // namespace llvm + +#endif // LLVM_OBJECT_MUTABLEOBJECT_H Index: llvm/lib/Object/CMakeLists.txt =================================================================== --- llvm/lib/Object/CMakeLists.txt +++ llvm/lib/Object/CMakeLists.txt @@ -15,6 +15,8 @@ MachOUniversal.cpp Minidump.cpp ModuleSymbolTable.cpp + MutableELFObject.cpp + MutableObject.cpp Object.cpp ObjectFile.cpp RecordStreamer.cpp Index: llvm/lib/Object/MutableObject.cpp =================================================================== --- /dev/null +++ llvm/lib/Object/MutableObject.cpp @@ -0,0 +1,74 @@ +#include "llvm/Object/MutableObject.h" + +namespace llvm { +namespace object { +namespace mutable_object { + +SectionBase::SectionBase(const MutableObject &OwningObject, + ArrayRef Data, StringRef Name) +: OwningObject(OwningObject), Data(Data), Name(Name) {} + +StringRef SectionBase::name() const { + return Name; +} + +ArrayRef SectionBase::data() const { + return Data; +} + +const MutableObject &SectionBase::getOwningObject() const { + return OwningObject; +} + +SegmentBase::SegmentBase(const MutableObject &OwningObject) +: OwningObject(OwningObject) {} + +void SegmentBase::removeSection(uint64_t Section) { + Sections.erase(Section); +} + +void SegmentBase::addSection(uint64_t Section) { + Sections.insert(Section); +} + +const ObjectFile &MutableObject::getObjectFile() const { + return ObjFile; +} + +Optional MutableObject::findSectionByName(StringRef Name) const { + auto Range = sections(); + const auto End = Range.end(); + for (auto Iter = Range.begin(); Iter != End; ++Iter) + if (Iter->name() == Name) + return Iter.getCurrentDataRef(); + return None; +} + +Error MutableObject::removeSection(DataRef Section) { + return Sections.remove(Section); +} + +Error MutableObject::replaceSection(DataRef ToReplace, + std::unique_ptr New) { + return Sections.update(ToReplace, std::move(New)); +} + +MutableObjectRange MutableObject::sections() const { + return MutableObjectRange(Sections); +} + +MutableObjectRange MutableObject::segments() const { + return MutableObjectRange(Segments); +} + +SectionBase &MutableObject::getMutableSection(DataRef Section) { + Sections.getNew(Section); +} + +SegmentBase &MutableObject::getMutableSegment(DataRef Segment) { + Segments.getNew(Segment); +} + +} // namespace mutable_object +} // namespace object +} // namespace llvm