| Chris Bieneman | b83c187 | 2016-05-11 22:07:48 +0000 | [diff] [blame] | 1 | //===- yaml2macho - Convert YAML to a Mach object file --------------------===// | 
|  | 2 | // | 
|  | 3 | //                     The LLVM Compiler Infrastructure | 
|  | 4 | // | 
|  | 5 | // This file is distributed under the University of Illinois Open Source | 
|  | 6 | // License. See LICENSE.TXT for details. | 
|  | 7 | // | 
|  | 8 | //===----------------------------------------------------------------------===// | 
|  | 9 | /// | 
|  | 10 | /// \file | 
|  | 11 | /// \brief The Mach component of yaml2obj. | 
|  | 12 | /// | 
|  | 13 | //===----------------------------------------------------------------------===// | 
|  | 14 |  | 
|  | 15 | #include "yaml2obj.h" | 
| Chris Bieneman | a23b26f | 2016-05-12 17:44:48 +0000 | [diff] [blame] | 16 | #include "llvm/ObjectYAML/MachOYAML.h" | 
|  | 17 | #include "llvm/Support/Error.h" | 
|  | 18 | #include "llvm/Support/MachO.h" | 
|  | 19 | #include "llvm/Support/YAMLTraits.h" | 
| Chris Bieneman | b83c187 | 2016-05-11 22:07:48 +0000 | [diff] [blame] | 20 | #include "llvm/Support/raw_ostream.h" | 
|  | 21 |  | 
|  | 22 | using namespace llvm; | 
|  | 23 |  | 
| Chris Bieneman | a23b26f | 2016-05-12 17:44:48 +0000 | [diff] [blame] | 24 | namespace { | 
|  | 25 |  | 
|  | 26 | class MachOWriter { | 
|  | 27 | public: | 
|  | 28 | MachOWriter(MachOYAML::Object &Obj) : Obj(Obj) { | 
|  | 29 | is64Bit = Obj.Header.magic == MachO::MH_MAGIC_64 || | 
|  | 30 | Obj.Header.magic == MachO::MH_CIGAM_64; | 
| Chris Bieneman | 26e6cea | 2016-05-12 18:02:13 +0000 | [diff] [blame] | 31 | memset(reinterpret_cast<void *>(&Header64), 0, | 
|  | 32 | sizeof(MachO::mach_header_64)); | 
| Chris Bieneman | fc88927 | 2016-05-12 18:21:09 +0000 | [diff] [blame] | 33 | assert((is64Bit || Obj.Header.reserved == 0xDEADBEEFu) && | 
|  | 34 | "32-bit MachO has reserved in header"); | 
|  | 35 | assert((!is64Bit || Obj.Header.reserved != 0xDEADBEEFu) && | 
|  | 36 | "64-bit MachO has missing reserved in header"); | 
| Chris Bieneman | a23b26f | 2016-05-12 17:44:48 +0000 | [diff] [blame] | 37 | } | 
|  | 38 |  | 
|  | 39 | Error writeMachO(raw_ostream &OS); | 
|  | 40 |  | 
|  | 41 | private: | 
|  | 42 | Error writeHeader(raw_ostream &OS); | 
| Chris Bieneman | 8b5906e | 2016-05-13 17:41:41 +0000 | [diff] [blame] | 43 | Error writeLoadCommands(raw_ostream &OS); | 
| Chris Bieneman | a23b26f | 2016-05-12 17:44:48 +0000 | [diff] [blame] | 44 |  | 
| Chris Bieneman | 8b5906e | 2016-05-13 17:41:41 +0000 | [diff] [blame] | 45 | MachOYAML::Object &Obj; | 
| Chris Bieneman | a23b26f | 2016-05-12 17:44:48 +0000 | [diff] [blame] | 46 | bool is64Bit; | 
|  | 47 |  | 
|  | 48 | union { | 
|  | 49 | MachO::mach_header_64 Header64; | 
|  | 50 | MachO::mach_header Header; | 
|  | 51 | }; | 
|  | 52 | }; | 
|  | 53 |  | 
|  | 54 | Error MachOWriter::writeMachO(raw_ostream &OS) { | 
|  | 55 | if (auto Err = writeHeader(OS)) | 
|  | 56 | return Err; | 
| Chris Bieneman | 8b5906e | 2016-05-13 17:41:41 +0000 | [diff] [blame] | 57 | if (auto Err = writeLoadCommands(OS)) | 
|  | 58 | return Err; | 
| Chris Bieneman | a23b26f | 2016-05-12 17:44:48 +0000 | [diff] [blame] | 59 | return Error::success(); | 
|  | 60 | } | 
|  | 61 |  | 
|  | 62 | Error MachOWriter::writeHeader(raw_ostream &OS) { | 
|  | 63 | Header.magic = Obj.Header.magic; | 
|  | 64 | Header.cputype = Obj.Header.cputype; | 
|  | 65 | Header.cpusubtype = Obj.Header.cpusubtype; | 
|  | 66 | Header.filetype = Obj.Header.filetype; | 
|  | 67 | Header.ncmds = Obj.Header.ncmds; | 
|  | 68 | Header.sizeofcmds = Obj.Header.sizeofcmds; | 
|  | 69 | Header.flags = Obj.Header.flags; | 
| Chris Bieneman | fc88927 | 2016-05-12 18:21:09 +0000 | [diff] [blame] | 70 | Header64.reserved = Obj.Header.reserved; | 
| Chris Bieneman | a23b26f | 2016-05-12 17:44:48 +0000 | [diff] [blame] | 71 |  | 
| Chris Bieneman | 8b5906e | 2016-05-13 17:41:41 +0000 | [diff] [blame] | 72 | if (is64Bit) | 
| Chris Bieneman | a23b26f | 2016-05-12 17:44:48 +0000 | [diff] [blame] | 73 | OS.write((const char *)&Header64, sizeof(MachO::mach_header_64)); | 
|  | 74 | else | 
|  | 75 | OS.write((const char *)&Header, sizeof(MachO::mach_header)); | 
|  | 76 |  | 
|  | 77 | return Error::success(); | 
|  | 78 | } | 
|  | 79 |  | 
| Chris Bieneman | 2de17d4 | 2016-05-18 16:17:23 +0000 | [diff] [blame] | 80 | template <typename SectionType> | 
|  | 81 | SectionType constructSection(MachOYAML::Section Sec) { | 
|  | 82 | SectionType TempSec; | 
|  | 83 | memcpy(reinterpret_cast<void *>(&TempSec.sectname[0]), &Sec.sectname[0], 16); | 
|  | 84 | memcpy(reinterpret_cast<void *>(&TempSec.segname[0]), &Sec.segname[0], 16); | 
|  | 85 | TempSec.addr = Sec.addr; | 
|  | 86 | TempSec.size = Sec.size; | 
|  | 87 | TempSec.offset = Sec.offset; | 
|  | 88 | TempSec.align = Sec.align; | 
|  | 89 | TempSec.reloff = Sec.reloff; | 
|  | 90 | TempSec.nreloc = Sec.nreloc; | 
|  | 91 | TempSec.flags = Sec.flags; | 
|  | 92 | TempSec.reserved1 = Sec.reserved1; | 
|  | 93 | TempSec.reserved2 = Sec.reserved2; | 
|  | 94 | return TempSec; | 
|  | 95 | } | 
|  | 96 |  | 
| Chris Bieneman | 9f243e9 | 2016-05-19 20:54:43 +0000 | [diff] [blame] | 97 | template <typename StructType> | 
|  | 98 | size_t writeLoadCommandData(MachOYAML::LoadCommand &LC, raw_ostream &OS) { | 
|  | 99 | return 0; | 
|  | 100 | } | 
|  | 101 |  | 
|  | 102 | template <> | 
|  | 103 | size_t writeLoadCommandData<MachO::segment_command>(MachOYAML::LoadCommand &LC, | 
|  | 104 | raw_ostream &OS) { | 
|  | 105 | size_t BytesWritten = 0; | 
|  | 106 | for (auto Sec : LC.Sections) { | 
|  | 107 | auto TempSec = constructSection<MachO::section>(Sec); | 
|  | 108 | OS.write(reinterpret_cast<const char *>(&(TempSec)), | 
|  | 109 | sizeof(MachO::section)); | 
|  | 110 | BytesWritten += sizeof(MachO::section); | 
|  | 111 | } | 
|  | 112 | return BytesWritten; | 
|  | 113 | } | 
|  | 114 |  | 
|  | 115 | template <> | 
|  | 116 | size_t | 
|  | 117 | writeLoadCommandData<MachO::segment_command_64>(MachOYAML::LoadCommand &LC, | 
|  | 118 | raw_ostream &OS) { | 
|  | 119 | size_t BytesWritten = 0; | 
|  | 120 | for (auto Sec : LC.Sections) { | 
|  | 121 | auto TempSec = constructSection<MachO::section_64>(Sec); | 
|  | 122 | TempSec.reserved3 = Sec.reserved3; | 
|  | 123 | OS.write(reinterpret_cast<const char *>(&(TempSec)), | 
|  | 124 | sizeof(MachO::section_64)); | 
|  | 125 | BytesWritten += sizeof(MachO::section_64); | 
|  | 126 | } | 
|  | 127 | return BytesWritten; | 
|  | 128 | } | 
|  | 129 |  | 
|  | 130 | size_t writePayloadString(MachOYAML::LoadCommand &LC, raw_ostream &OS) { | 
|  | 131 | size_t BytesWritten = 0; | 
|  | 132 | if (!LC.PayloadString.empty()) { | 
|  | 133 | OS.write(LC.PayloadString.c_str(), LC.PayloadString.length()); | 
|  | 134 | BytesWritten = LC.PayloadString.length(); | 
|  | 135 | } | 
|  | 136 | return BytesWritten; | 
|  | 137 | } | 
|  | 138 |  | 
|  | 139 | template <> | 
|  | 140 | size_t writeLoadCommandData<MachO::dylib_command>(MachOYAML::LoadCommand &LC, | 
|  | 141 | raw_ostream &OS) { | 
|  | 142 | return writePayloadString(LC, OS); | 
|  | 143 | } | 
|  | 144 |  | 
|  | 145 | template <> | 
|  | 146 | size_t writeLoadCommandData<MachO::dylinker_command>(MachOYAML::LoadCommand &LC, | 
|  | 147 | raw_ostream &OS) { | 
|  | 148 | return writePayloadString(LC, OS); | 
|  | 149 | } | 
|  | 150 |  | 
| Chris Bieneman | 8b5906e | 2016-05-13 17:41:41 +0000 | [diff] [blame] | 151 | Error MachOWriter::writeLoadCommands(raw_ostream &OS) { | 
|  | 152 | for (auto &LC : Obj.LoadCommands) { | 
| Chris Bieneman | 3f2eb83 | 2016-05-17 19:44:06 +0000 | [diff] [blame] | 153 | size_t BytesWritten = 0; | 
|  | 154 | #define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct)                         \ | 
|  | 155 | case MachO::LCName:                                                          \ | 
|  | 156 | OS.write(reinterpret_cast<const char *>(&(LC.Data.LCStruct##_data)),       \ | 
|  | 157 | sizeof(MachO::LCStruct));                                         \ | 
|  | 158 | BytesWritten = sizeof(MachO::LCStruct);                                    \ | 
| Chris Bieneman | 9f243e9 | 2016-05-19 20:54:43 +0000 | [diff] [blame] | 159 | BytesWritten += writeLoadCommandData<MachO::LCStruct>(LC, OS);             \ | 
| Chris Bieneman | 3f2eb83 | 2016-05-17 19:44:06 +0000 | [diff] [blame] | 160 | break; | 
|  | 161 |  | 
|  | 162 | switch (LC.Data.load_command_data.cmd) { | 
|  | 163 | default: | 
|  | 164 | OS.write(reinterpret_cast<const char *>(&(LC.Data.load_command_data)), | 
|  | 165 | sizeof(MachO::load_command)); | 
|  | 166 | BytesWritten = sizeof(MachO::load_command); | 
| Chris Bieneman | 9f243e9 | 2016-05-19 20:54:43 +0000 | [diff] [blame] | 167 | BytesWritten += writeLoadCommandData<MachO::load_command>(LC, OS); | 
| Chris Bieneman | 3f2eb83 | 2016-05-17 19:44:06 +0000 | [diff] [blame] | 168 | break; | 
|  | 169 | #include "llvm/Support/MachO.def" | 
|  | 170 | } | 
|  | 171 |  | 
| Chris Bieneman | 9f243e9 | 2016-05-19 20:54:43 +0000 | [diff] [blame] | 172 | if (LC.PayloadBytes.size() > 0) { | 
|  | 173 | OS.write(reinterpret_cast<const char *>(LC.PayloadBytes.data()), | 
|  | 174 | LC.PayloadBytes.size()); | 
|  | 175 | BytesWritten += LC.PayloadBytes.size(); | 
| Chris Bieneman | 2de17d4 | 2016-05-18 16:17:23 +0000 | [diff] [blame] | 176 | } | 
|  | 177 |  | 
| Chris Bieneman | 9f243e9 | 2016-05-19 20:54:43 +0000 | [diff] [blame] | 178 | if (LC.ZeroPadBytes > 0) { | 
|  | 179 | std::vector<uint8_t> FillData; | 
|  | 180 | FillData.insert(FillData.begin(), LC.ZeroPadBytes, 0); | 
|  | 181 | OS.write(reinterpret_cast<char *>(FillData.data()), LC.ZeroPadBytes); | 
|  | 182 | BytesWritten += LC.ZeroPadBytes; | 
|  | 183 | } | 
|  | 184 |  | 
| Chris Bieneman | 1abf005 | 2016-05-19 23:26:31 +0000 | [diff] [blame^] | 185 | // Fill remaining bytes with 0. This will only get hit in partially | 
|  | 186 | // specified test cases. | 
| Chris Bieneman | 9f243e9 | 2016-05-19 20:54:43 +0000 | [diff] [blame] | 187 | auto BytesRemaining = LC.Data.load_command_data.cmdsize - BytesWritten; | 
| Chris Bieneman | 3f2eb83 | 2016-05-17 19:44:06 +0000 | [diff] [blame] | 188 | if (BytesRemaining > 0) { | 
| Chris Bieneman | 3f2eb83 | 2016-05-17 19:44:06 +0000 | [diff] [blame] | 189 | std::vector<uint32_t> FillData; | 
| Chris Bieneman | 1abf005 | 2016-05-19 23:26:31 +0000 | [diff] [blame^] | 190 | FillData.insert(FillData.begin(), BytesRemaining, 0); | 
| Chris Bieneman | 3f2eb83 | 2016-05-17 19:44:06 +0000 | [diff] [blame] | 191 | OS.write(reinterpret_cast<char *>(FillData.data()), BytesRemaining); | 
| Chris Bieneman | 8b5906e | 2016-05-13 17:41:41 +0000 | [diff] [blame] | 192 | } | 
|  | 193 | } | 
|  | 194 | return Error::success(); | 
|  | 195 | } | 
|  | 196 |  | 
| Chris Bieneman | a23b26f | 2016-05-12 17:44:48 +0000 | [diff] [blame] | 197 | } // end anonymous namespace | 
|  | 198 |  | 
|  | 199 | int yaml2macho(yaml::Input &YIn, raw_ostream &Out) { | 
|  | 200 | MachOYAML::Object Doc; | 
|  | 201 | YIn >> Doc; | 
|  | 202 | if (YIn.error()) { | 
|  | 203 | errs() << "yaml2obj: Failed to parse YAML file!\n"; | 
|  | 204 | return 1; | 
|  | 205 | } | 
|  | 206 |  | 
|  | 207 | MachOWriter Writer(Doc); | 
|  | 208 | if (auto Err = Writer.writeMachO(Out)) { | 
|  | 209 | errs() << toString(std::move(Err)); | 
|  | 210 | return 1; | 
|  | 211 | } | 
|  | 212 | return 0; | 
| Chris Bieneman | b83c187 | 2016-05-11 22:07:48 +0000 | [diff] [blame] | 213 | } |