Index: llvm/include/llvm/Object/MutableObject.h =================================================================== --- /dev/null +++ llvm/include/llvm/Object/MutableObject.h @@ -0,0 +1,144 @@ +//===- MutableObject.h - An object file which can be mutated ----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This class represents an object file which can be mutated, then recreated +// to reflect the changes. +// +//===----------------------------------------------------------------------===// + +#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 +#include + +namespace llvm { +namespace object { +namespace mutable_object { + +/// Leaves an original vector of Entity's immutable but provides ways to +/// create new Entity's and allow mutations of the new ones. This makes it +/// possible to retain original information and mutate at the same time. +template +class UpdatableList { +public: + using Ptr = std::unique_ptr; + using OriginalType = std::vector; +private: + const OriginalType Original; + std::unordered_map Updated; + + // Represents the largest number of Entity's in the list This is used for + // createNew which will insert into the map with a key of CurrentNum++. + uint64_t CurrentNum = 0; +public: + UpdatableList() = default; + UpdatableList(const UpdatableList &) = delete; + //UpdatableList(UpdatableList &&) = default; + UpdatableList(OriginalType Original) + : Original(std::move(Original)), CurrentNum(Original.size()) {} + + const Entity &operator[](uint64_t Index) const { + auto Found = Updated.find(Index); + if (Found != Updated.end()) { + assert(Found->second.get() && "Section was deleted"); + 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. If a section has not yet been created as + // mutable, create it and return the newly created mutable Entity. + Entity &getUpdated(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 replace(uint64_t Index, Ptr New) { + if (Updated.find(Index) == Updated.end()) { + if (Index >= Original.size()) + return createStringError(errc::argument_out_of_domain, + "Updating section that doesn't exist"); + } + Updated[Index] = std::move(New); + return Error::success(); + } + + Error remove(uint64_t Index) { + return replace(Index, nullptr); + } + + // Adds a new mutable Entity to the end of the list and + // returns a reference to it. + Entity &addNew() { + const Entity &First = getOriginal(0); + Updated[CurrentNum] = First.clone(); + return *Updated.find(CurrentNum++)->second; + } + + template Entity &addNew(Ts &&... Args) { + Updated[CurrentNum] = make_unique(std::forward(Args)...); + return *Updated.find(CurrentNum++)->second; + } +}; + +class SectionBase {}; +class SegmentBase {}; + +class MutableObject { +protected: + using SectionList = UpdatableList; + using SegmentList = UpdatableList; + + const ObjectFile &ObjFile; + + SectionList Sections; + SegmentList Segments; + + MutableObject(const ObjectFile &ObjFile, SectionList::OriginalType OriginalSections, SegmentList::OriginalType OriginalSegments); +public: + virtual ~MutableObject() {} + + static Expected> + createMutableObject(const ObjectFile &ObjFile); + + const ObjectFile *getObjectFile() const { return &ObjFile; } + + Error removeSection(uint64_t Section) { Sections.remove(Section); } + Error replaceSection(uint64_t ToReplace, std::unique_ptr New) { + Sections.replace(ToReplace, std::move(New)); + } + + SectionBase &getMutableSection(uint64_t Section) { Sections.getUpdated(Section); } + SegmentBase &getMutableSegment(uint64_t Segment) { Segments.getUpdated(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,7 @@ MachOUniversal.cpp Minidump.cpp ModuleSymbolTable.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,33 @@ +//===- MutableObject.h - An object file which can be mutated ----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This class represents an object file which can be mutated, then recreated +// to reflect the changes. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Object/MutableObject.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Object/ELFObjectFile.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/Casting.h" + +using namespace llvm; +using namespace object; +using namespace mutable_object; + +MutableObject::MutableObject(const ObjectFile &ObjFile, SectionList::OriginalType OriginalSections, SegmentList::OriginalType OriginalSegments) +: ObjFile(ObjFile), Sections(std::move(OriginalSections)), Segments(std::move(OriginalSegments)) {} + +Expected> MutableObject::createMutableObject(const ObjectFile &ObjFile) { + // TODO: check type of ObjFile and call the static create methods of the + // corresponding derived class. + + return createStringError(errc::not_supported, "Unkown filetype"); +}