diff options
-rw-r--r-- | llvm/include/llvm/ObjectYAML/MachOYAML.h | 4 | ||||
-rw-r--r-- | llvm/lib/ObjectYAML/MachOYAML.cpp | 34 | ||||
-rw-r--r-- | llvm/tools/obj2yaml/macho2yaml.cpp | 80 | ||||
-rw-r--r-- | llvm/tools/yaml2obj/yaml2macho.cpp | 83 |
4 files changed, 170 insertions, 31 deletions
diff --git a/llvm/include/llvm/ObjectYAML/MachOYAML.h b/llvm/include/llvm/ObjectYAML/MachOYAML.h index 3c79a20c55a..cb29c6dcd62 100644 --- a/llvm/include/llvm/ObjectYAML/MachOYAML.h +++ b/llvm/include/llvm/ObjectYAML/MachOYAML.h @@ -52,6 +52,9 @@ struct LoadCommand { virtual ~LoadCommand(); llvm::MachO::macho_load_command Data; std::vector<Section> Sections; + std::vector<llvm::yaml::Hex8> PayloadBytes; + std::string PayloadString; + uint64_t ZeroPadBytes; }; struct Object { @@ -65,6 +68,7 @@ struct Object { LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::LoadCommand) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::Section) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::Hex8) namespace llvm { namespace yaml { diff --git a/llvm/lib/ObjectYAML/MachOYAML.cpp b/llvm/lib/ObjectYAML/MachOYAML.cpp index 2faefca432e..60ed53f7d1e 100644 --- a/llvm/lib/ObjectYAML/MachOYAML.cpp +++ b/llvm/lib/ObjectYAML/MachOYAML.cpp @@ -96,6 +96,33 @@ void MappingTraits<MachOYAML::Object>::mapping(IO &IO, IO.setContext(nullptr); } +template <typename StructType> +void mapLoadCommandData(IO &IO, MachOYAML::LoadCommand &LoadCommand) {} + +template <> +void mapLoadCommandData<MachO::segment_command>( + IO &IO, MachOYAML::LoadCommand &LoadCommand) { + IO.mapOptional("Sections", LoadCommand.Sections); +} + +template <> +void mapLoadCommandData<MachO::segment_command_64>( + IO &IO, MachOYAML::LoadCommand &LoadCommand) { + IO.mapOptional("Sections", LoadCommand.Sections); +} + +template <> +void mapLoadCommandData<MachO::dylib_command>( + IO &IO, MachOYAML::LoadCommand &LoadCommand) { + IO.mapOptional("PayloadString", LoadCommand.PayloadString); +} + +template <> +void mapLoadCommandData<MachO::dylinker_command>( + IO &IO, MachOYAML::LoadCommand &LoadCommand) { + IO.mapOptional("PayloadString", LoadCommand.PayloadString); +} + void MappingTraits<MachOYAML::LoadCommand>::mapping( IO &IO, MachOYAML::LoadCommand &LoadCommand) { IO.mapRequired( @@ -106,15 +133,14 @@ void MappingTraits<MachOYAML::LoadCommand>::mapping( case MachO::LCName: \ MappingTraits<MachO::LCStruct>::mapping(IO, \ LoadCommand.Data.LCStruct##_data); \ + mapLoadCommandData<MachO::LCStruct>(IO, LoadCommand); \ break; switch (LoadCommand.Data.load_command_data.cmd) { #include "llvm/Support/MachO.def" } - if (LoadCommand.Data.load_command_data.cmd == MachO::LC_SEGMENT || - LoadCommand.Data.load_command_data.cmd == MachO::LC_SEGMENT_64) { - IO.mapOptional("Sections", LoadCommand.Sections); - } + IO.mapOptional("PayloadBytes", LoadCommand.PayloadBytes); + IO.mapOptional("ZeroPadBytes", LoadCommand.ZeroPadBytes, 0ull); } void MappingTraits<MachO::dyld_info_command>::mapping( diff --git a/llvm/tools/obj2yaml/macho2yaml.cpp b/llvm/tools/obj2yaml/macho2yaml.cpp index b90147403bd..eae15533d07 100644 --- a/llvm/tools/obj2yaml/macho2yaml.cpp +++ b/llvm/tools/obj2yaml/macho2yaml.cpp @@ -19,6 +19,11 @@ using namespace llvm; class MachODumper { + template <typename StructType> + const char *processLoadCommandData( + MachOYAML::LoadCommand &LC, + const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd); + const object::MachOObjectFile &Obj; public: @@ -32,6 +37,7 @@ public: sizeof(MachO::LCStruct)); \ if (Obj.isLittleEndian() != sys::IsLittleEndianHost) \ MachO::swapStruct(LC.Data.LCStruct##_data); \ + EndPtr = processLoadCommandData<MachO::LCStruct>(LC, LoadCmd); \ break; template <typename SectionType> @@ -68,9 +74,10 @@ template <> MachOYAML::Section constructSection(MachO::section_64 Sec) { } template <typename SectionType, typename SegmentType> -void extractSections( - const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd, - std::vector<MachOYAML::Section> &Sections, bool IsLittleEndian) { +const char * +extractSections(const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd, + std::vector<MachOYAML::Section> &Sections, + bool IsLittleEndian) { auto End = LoadCmd.Ptr + LoadCmd.C.cmdsize; const SectionType *Curr = reinterpret_cast<const SectionType *>(LoadCmd.Ptr + sizeof(SegmentType)); @@ -84,6 +91,55 @@ void extractSections( Sections.push_back(constructSection(*Curr)); } } + return reinterpret_cast<const char *>(Curr); +} + +template <typename StructType> +const char *MachODumper::processLoadCommandData( + MachOYAML::LoadCommand &LC, + const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd) { + return LoadCmd.Ptr + sizeof(StructType); +} + +template <> +const char *MachODumper::processLoadCommandData<MachO::segment_command>( + MachOYAML::LoadCommand &LC, + const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd) { + return extractSections<MachO::section, MachO::segment_command>( + LoadCmd, LC.Sections, Obj.isLittleEndian()); +} + +template <> +const char *MachODumper::processLoadCommandData<MachO::segment_command_64>( + MachOYAML::LoadCommand &LC, + const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd) { + return extractSections<MachO::section_64, MachO::segment_command_64>( + LoadCmd, LC.Sections, Obj.isLittleEndian()); +} + +template <typename StructType> +const char * +readString(MachOYAML::LoadCommand &LC, + const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd) { + auto Start = LoadCmd.Ptr + sizeof(StructType); + auto MaxSize = LoadCmd.C.cmdsize - sizeof(StructType); + auto Size = strnlen(Start, MaxSize); + LC.PayloadString = StringRef(Start, Size).str(); + return Start + Size; +} + +template <> +const char *MachODumper::processLoadCommandData<MachO::dylib_command>( + MachOYAML::LoadCommand &LC, + const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd) { + return readString<MachO::dylib_command>(LC, LoadCmd); +} + +template <> +const char *MachODumper::processLoadCommandData<MachO::dylinker_command>( + MachOYAML::LoadCommand &LC, + const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd) { + return readString<MachO::dylinker_command>(LC, LoadCmd); } Expected<std::unique_ptr<MachOYAML::Object>> MachODumper::dump() { @@ -99,25 +155,25 @@ Expected<std::unique_ptr<MachOYAML::Object>> MachODumper::dump() { for (auto LoadCmd : Obj.load_commands()) { MachOYAML::LoadCommand LC; + const char *EndPtr = LoadCmd.Ptr; switch (LoadCmd.C.cmd) { default: memcpy((void *)&(LC.Data.load_command_data), LoadCmd.Ptr, sizeof(MachO::load_command)); if (Obj.isLittleEndian() != sys::IsLittleEndianHost) MachO::swapStruct(LC.Data.load_command_data); + EndPtr = processLoadCommandData<MachO::load_command>(LC, LoadCmd); break; #include "llvm/Support/MachO.def" } - switch (LoadCmd.C.cmd) { - case MachO::LC_SEGMENT: - extractSections<MachO::section, MachO::segment_command>( - LoadCmd, LC.Sections, Obj.isLittleEndian()); - break; - case MachO::LC_SEGMENT_64: - extractSections<MachO::section_64, MachO::segment_command_64>( - LoadCmd, LC.Sections, Obj.isLittleEndian()); - break; + auto RemainingBytes = LoadCmd.C.cmdsize - (EndPtr - LoadCmd.Ptr); + if (!std::all_of(EndPtr, &EndPtr[RemainingBytes], + [](const char C) { return C == 0; })) { + LC.PayloadBytes.insert(LC.PayloadBytes.end(), EndPtr, + &EndPtr[RemainingBytes]); + RemainingBytes = 0; } + LC.ZeroPadBytes = RemainingBytes; Y->LoadCommands.push_back(std::move(LC)); } diff --git a/llvm/tools/yaml2obj/yaml2macho.cpp b/llvm/tools/yaml2obj/yaml2macho.cpp index 0e8799e2ce1..2a1c6a7e9d2 100644 --- a/llvm/tools/yaml2obj/yaml2macho.cpp +++ b/llvm/tools/yaml2obj/yaml2macho.cpp @@ -94,6 +94,60 @@ SectionType constructSection(MachOYAML::Section Sec) { return TempSec; } +template <typename StructType> +size_t writeLoadCommandData(MachOYAML::LoadCommand &LC, raw_ostream &OS) { + return 0; +} + +template <> +size_t writeLoadCommandData<MachO::segment_command>(MachOYAML::LoadCommand &LC, + raw_ostream &OS) { + size_t BytesWritten = 0; + for (auto Sec : LC.Sections) { + auto TempSec = constructSection<MachO::section>(Sec); + OS.write(reinterpret_cast<const char *>(&(TempSec)), + sizeof(MachO::section)); + BytesWritten += sizeof(MachO::section); + } + return BytesWritten; +} + +template <> +size_t +writeLoadCommandData<MachO::segment_command_64>(MachOYAML::LoadCommand &LC, + raw_ostream &OS) { + size_t BytesWritten = 0; + for (auto Sec : LC.Sections) { + auto TempSec = constructSection<MachO::section_64>(Sec); + TempSec.reserved3 = Sec.reserved3; + OS.write(reinterpret_cast<const char *>(&(TempSec)), + sizeof(MachO::section_64)); + BytesWritten += sizeof(MachO::section_64); + } + return BytesWritten; +} + +size_t writePayloadString(MachOYAML::LoadCommand &LC, raw_ostream &OS) { + size_t BytesWritten = 0; + if (!LC.PayloadString.empty()) { + OS.write(LC.PayloadString.c_str(), LC.PayloadString.length()); + BytesWritten = LC.PayloadString.length(); + } + return BytesWritten; +} + +template <> +size_t writeLoadCommandData<MachO::dylib_command>(MachOYAML::LoadCommand &LC, + raw_ostream &OS) { + return writePayloadString(LC, OS); +} + +template <> +size_t writeLoadCommandData<MachO::dylinker_command>(MachOYAML::LoadCommand &LC, + raw_ostream &OS) { + return writePayloadString(LC, OS); +} + Error MachOWriter::writeLoadCommands(raw_ostream &OS) { for (auto &LC : Obj.LoadCommands) { size_t BytesWritten = 0; @@ -102,6 +156,7 @@ Error MachOWriter::writeLoadCommands(raw_ostream &OS) { OS.write(reinterpret_cast<const char *>(&(LC.Data.LCStruct##_data)), \ sizeof(MachO::LCStruct)); \ BytesWritten = sizeof(MachO::LCStruct); \ + BytesWritten += writeLoadCommandData<MachO::LCStruct>(LC, OS); \ break; switch (LC.Data.load_command_data.cmd) { @@ -109,27 +164,25 @@ Error MachOWriter::writeLoadCommands(raw_ostream &OS) { OS.write(reinterpret_cast<const char *>(&(LC.Data.load_command_data)), sizeof(MachO::load_command)); BytesWritten = sizeof(MachO::load_command); + BytesWritten += writeLoadCommandData<MachO::load_command>(LC, OS); break; #include "llvm/Support/MachO.def" } - if(LC.Data.load_command_data.cmd == MachO::LC_SEGMENT) { - for(auto Sec : LC.Sections) { - auto TempSec = constructSection<MachO::section>(Sec); - OS.write(reinterpret_cast<const char *>(&(TempSec)), sizeof(MachO::section)); - BytesWritten += sizeof(MachO::section); - } - } else if(LC.Data.load_command_data.cmd == MachO::LC_SEGMENT_64) { - for(auto Sec : LC.Sections) { - auto TempSec = constructSection<MachO::section_64>(Sec); - TempSec.reserved3 = Sec.reserved3; - OS.write(reinterpret_cast<const char *>(&(TempSec)), sizeof(MachO::section_64)); - BytesWritten += sizeof(MachO::section_64); - } + if (LC.PayloadBytes.size() > 0) { + OS.write(reinterpret_cast<const char *>(LC.PayloadBytes.data()), + LC.PayloadBytes.size()); + BytesWritten += LC.PayloadBytes.size(); + } + + if (LC.ZeroPadBytes > 0) { + std::vector<uint8_t> FillData; + FillData.insert(FillData.begin(), LC.ZeroPadBytes, 0); + OS.write(reinterpret_cast<char *>(FillData.data()), LC.ZeroPadBytes); + BytesWritten += LC.ZeroPadBytes; } - auto BytesRemaining = - LC.Data.load_command_data.cmdsize - BytesWritten; + auto BytesRemaining = LC.Data.load_command_data.cmdsize - BytesWritten; if (BytesRemaining > 0) { // TODO: Replace all this once the load command data is present in yaml. // For now I fill with 0xDEADBEEF because it is easy to spot on a hex |