blob: 6d71eef67bcb1501e1e7f8cb2b4ed34f1a249398 [file] [log] [blame]
Chris Bienemanb83c1872016-05-11 22:07:48 +00001//===- 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 Bienemana23b26f2016-05-12 17:44:48 +000016#include "llvm/ObjectYAML/MachOYAML.h"
17#include "llvm/Support/Error.h"
18#include "llvm/Support/MachO.h"
19#include "llvm/Support/YAMLTraits.h"
Chris Bienemanb83c1872016-05-11 22:07:48 +000020#include "llvm/Support/raw_ostream.h"
21
22using namespace llvm;
23
Chris Bienemana23b26f2016-05-12 17:44:48 +000024namespace {
25
26class MachOWriter {
27public:
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 Bieneman26e6cea2016-05-12 18:02:13 +000031 memset(reinterpret_cast<void *>(&Header64), 0,
32 sizeof(MachO::mach_header_64));
Chris Bienemanfc889272016-05-12 18:21:09 +000033 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 Bienemana23b26f2016-05-12 17:44:48 +000037 }
38
39 Error writeMachO(raw_ostream &OS);
40
41private:
42 Error writeHeader(raw_ostream &OS);
Chris Bieneman8b5906e2016-05-13 17:41:41 +000043 Error writeLoadCommands(raw_ostream &OS);
Chris Bienemana23b26f2016-05-12 17:44:48 +000044
Chris Bieneman8b5906e2016-05-13 17:41:41 +000045 MachOYAML::Object &Obj;
Chris Bienemana23b26f2016-05-12 17:44:48 +000046 bool is64Bit;
47
48 union {
49 MachO::mach_header_64 Header64;
50 MachO::mach_header Header;
51 };
52};
53
54Error MachOWriter::writeMachO(raw_ostream &OS) {
55 if (auto Err = writeHeader(OS))
56 return Err;
Chris Bieneman8b5906e2016-05-13 17:41:41 +000057 if (auto Err = writeLoadCommands(OS))
58 return Err;
Chris Bienemana23b26f2016-05-12 17:44:48 +000059 return Error::success();
60}
61
62Error 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 Bienemanfc889272016-05-12 18:21:09 +000070 Header64.reserved = Obj.Header.reserved;
Chris Bienemana23b26f2016-05-12 17:44:48 +000071
Chris Bieneman8b5906e2016-05-13 17:41:41 +000072 if (is64Bit)
Chris Bienemana23b26f2016-05-12 17:44:48 +000073 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 Bieneman2de17d42016-05-18 16:17:23 +000080template <typename SectionType>
81SectionType 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 Bieneman9f243e92016-05-19 20:54:43 +000097template <typename StructType>
98size_t writeLoadCommandData(MachOYAML::LoadCommand &LC, raw_ostream &OS) {
99 return 0;
100}
101
102template <>
103size_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
115template <>
116size_t
117writeLoadCommandData<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
130size_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
139template <>
140size_t writeLoadCommandData<MachO::dylib_command>(MachOYAML::LoadCommand &LC,
141 raw_ostream &OS) {
142 return writePayloadString(LC, OS);
143}
144
145template <>
146size_t writeLoadCommandData<MachO::dylinker_command>(MachOYAML::LoadCommand &LC,
147 raw_ostream &OS) {
148 return writePayloadString(LC, OS);
149}
150
Chris Bieneman8b5906e2016-05-13 17:41:41 +0000151Error MachOWriter::writeLoadCommands(raw_ostream &OS) {
152 for (auto &LC : Obj.LoadCommands) {
Chris Bieneman3f2eb832016-05-17 19:44:06 +0000153 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 Bieneman9f243e92016-05-19 20:54:43 +0000159 BytesWritten += writeLoadCommandData<MachO::LCStruct>(LC, OS); \
Chris Bieneman3f2eb832016-05-17 19:44:06 +0000160 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 Bieneman9f243e92016-05-19 20:54:43 +0000167 BytesWritten += writeLoadCommandData<MachO::load_command>(LC, OS);
Chris Bieneman3f2eb832016-05-17 19:44:06 +0000168 break;
169#include "llvm/Support/MachO.def"
170 }
171
Chris Bieneman9f243e92016-05-19 20:54:43 +0000172 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 Bieneman2de17d42016-05-18 16:17:23 +0000176 }
177
Chris Bieneman9f243e92016-05-19 20:54:43 +0000178 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 Bieneman1abf0052016-05-19 23:26:31 +0000185 // Fill remaining bytes with 0. This will only get hit in partially
186 // specified test cases.
Chris Bieneman9f243e92016-05-19 20:54:43 +0000187 auto BytesRemaining = LC.Data.load_command_data.cmdsize - BytesWritten;
Chris Bieneman3f2eb832016-05-17 19:44:06 +0000188 if (BytesRemaining > 0) {
Chris Bieneman3f2eb832016-05-17 19:44:06 +0000189 std::vector<uint32_t> FillData;
Chris Bieneman1abf0052016-05-19 23:26:31 +0000190 FillData.insert(FillData.begin(), BytesRemaining, 0);
Chris Bieneman3f2eb832016-05-17 19:44:06 +0000191 OS.write(reinterpret_cast<char *>(FillData.data()), BytesRemaining);
Chris Bieneman8b5906e2016-05-13 17:41:41 +0000192 }
193 }
194 return Error::success();
195}
196
Chris Bienemana23b26f2016-05-12 17:44:48 +0000197} // end anonymous namespace
198
199int 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 Bienemanb83c1872016-05-11 22:07:48 +0000213}