File: | tools/yaml2obj/yaml2macho.cpp |
Location: | line 322, column 20 |
Description: | Access to field 'stroff' results in a dereference of a null pointer (loaded from variable 'SymtabCmd') |
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" | |||
16 | #include "llvm/ObjectYAML/MachOYAML.h" | |||
17 | #include "llvm/Support/Error.h" | |||
18 | #include "llvm/Support/LEB128.h" | |||
19 | #include "llvm/Support/MachO.h" | |||
20 | #include "llvm/Support/YAMLTraits.h" | |||
21 | #include "llvm/Support/raw_ostream.h" | |||
22 | ||||
23 | #include "llvm/Support/Format.h" | |||
24 | ||||
25 | using namespace llvm; | |||
26 | ||||
27 | namespace { | |||
28 | ||||
29 | class MachOWriter { | |||
30 | public: | |||
31 | MachOWriter(MachOYAML::Object &Obj) : Obj(Obj), is64Bit(true), fileStart(0) { | |||
32 | is64Bit = Obj.Header.magic == MachO::MH_MAGIC_64 || | |||
33 | Obj.Header.magic == MachO::MH_CIGAM_64; | |||
34 | memset(reinterpret_cast<void *>(&Header64), 0, | |||
35 | sizeof(MachO::mach_header_64)); | |||
36 | assert((is64Bit || Obj.Header.reserved == 0xDEADBEEFu) &&(((is64Bit || Obj.Header.reserved == 0xDEADBEEFu) && "32-bit MachO has reserved in header" ) ? static_cast<void> (0) : __assert_fail ("(is64Bit || Obj.Header.reserved == 0xDEADBEEFu) && \"32-bit MachO has reserved in header\"" , "/tmp/buildd/llvm-toolchain-snapshot-3.9~svn271203/tools/yaml2obj/yaml2macho.cpp" , 37, __PRETTY_FUNCTION__)) | |||
37 | "32-bit MachO has reserved in header")(((is64Bit || Obj.Header.reserved == 0xDEADBEEFu) && "32-bit MachO has reserved in header" ) ? static_cast<void> (0) : __assert_fail ("(is64Bit || Obj.Header.reserved == 0xDEADBEEFu) && \"32-bit MachO has reserved in header\"" , "/tmp/buildd/llvm-toolchain-snapshot-3.9~svn271203/tools/yaml2obj/yaml2macho.cpp" , 37, __PRETTY_FUNCTION__)); | |||
38 | assert((!is64Bit || Obj.Header.reserved != 0xDEADBEEFu) &&(((!is64Bit || Obj.Header.reserved != 0xDEADBEEFu) && "64-bit MachO has missing reserved in header") ? static_cast <void> (0) : __assert_fail ("(!is64Bit || Obj.Header.reserved != 0xDEADBEEFu) && \"64-bit MachO has missing reserved in header\"" , "/tmp/buildd/llvm-toolchain-snapshot-3.9~svn271203/tools/yaml2obj/yaml2macho.cpp" , 39, __PRETTY_FUNCTION__)) | |||
39 | "64-bit MachO has missing reserved in header")(((!is64Bit || Obj.Header.reserved != 0xDEADBEEFu) && "64-bit MachO has missing reserved in header") ? static_cast <void> (0) : __assert_fail ("(!is64Bit || Obj.Header.reserved != 0xDEADBEEFu) && \"64-bit MachO has missing reserved in header\"" , "/tmp/buildd/llvm-toolchain-snapshot-3.9~svn271203/tools/yaml2obj/yaml2macho.cpp" , 39, __PRETTY_FUNCTION__)); | |||
40 | } | |||
41 | ||||
42 | Error writeMachO(raw_ostream &OS); | |||
43 | ||||
44 | private: | |||
45 | Error writeHeader(raw_ostream &OS); | |||
46 | Error writeLoadCommands(raw_ostream &OS); | |||
47 | Error writeSectionData(raw_ostream &OS); | |||
48 | Error writeLinkEditData(raw_ostream &OS); | |||
49 | void writeBindOpcodes(raw_ostream &OS, uint64_t offset, | |||
50 | std::vector<MachOYAML::BindOpcode> &BindOpcodes); | |||
51 | ||||
52 | void ZeroToOffset(raw_ostream &OS, size_t offset); | |||
53 | ||||
54 | MachOYAML::Object &Obj; | |||
55 | bool is64Bit; | |||
56 | uint64_t fileStart; | |||
57 | ||||
58 | union { | |||
59 | MachO::mach_header_64 Header64; | |||
60 | MachO::mach_header Header; | |||
61 | }; | |||
62 | }; | |||
63 | ||||
64 | Error MachOWriter::writeMachO(raw_ostream &OS) { | |||
65 | fileStart = OS.tell(); | |||
66 | if (auto Err = writeHeader(OS)) | |||
67 | return Err; | |||
68 | if (auto Err = writeLoadCommands(OS)) | |||
69 | return Err; | |||
70 | if (auto Err = writeSectionData(OS)) | |||
71 | return Err; | |||
72 | return Error::success(); | |||
73 | } | |||
74 | ||||
75 | Error MachOWriter::writeHeader(raw_ostream &OS) { | |||
76 | Header.magic = Obj.Header.magic; | |||
77 | Header.cputype = Obj.Header.cputype; | |||
78 | Header.cpusubtype = Obj.Header.cpusubtype; | |||
79 | Header.filetype = Obj.Header.filetype; | |||
80 | Header.ncmds = Obj.Header.ncmds; | |||
81 | Header.sizeofcmds = Obj.Header.sizeofcmds; | |||
82 | Header.flags = Obj.Header.flags; | |||
83 | Header64.reserved = Obj.Header.reserved; | |||
84 | ||||
85 | if (is64Bit) | |||
86 | OS.write((const char *)&Header64, sizeof(MachO::mach_header_64)); | |||
87 | else | |||
88 | OS.write((const char *)&Header, sizeof(MachO::mach_header)); | |||
89 | ||||
90 | return Error::success(); | |||
91 | } | |||
92 | ||||
93 | template <typename SectionType> | |||
94 | SectionType constructSection(MachOYAML::Section Sec) { | |||
95 | SectionType TempSec; | |||
96 | memcpy(reinterpret_cast<void *>(&TempSec.sectname[0]), &Sec.sectname[0], 16); | |||
97 | memcpy(reinterpret_cast<void *>(&TempSec.segname[0]), &Sec.segname[0], 16); | |||
98 | TempSec.addr = Sec.addr; | |||
99 | TempSec.size = Sec.size; | |||
100 | TempSec.offset = Sec.offset; | |||
101 | TempSec.align = Sec.align; | |||
102 | TempSec.reloff = Sec.reloff; | |||
103 | TempSec.nreloc = Sec.nreloc; | |||
104 | TempSec.flags = Sec.flags; | |||
105 | TempSec.reserved1 = Sec.reserved1; | |||
106 | TempSec.reserved2 = Sec.reserved2; | |||
107 | return TempSec; | |||
108 | } | |||
109 | ||||
110 | template <typename StructType> | |||
111 | size_t writeLoadCommandData(MachOYAML::LoadCommand &LC, raw_ostream &OS) { | |||
112 | return 0; | |||
113 | } | |||
114 | ||||
115 | template <> | |||
116 | size_t writeLoadCommandData<MachO::segment_command>(MachOYAML::LoadCommand &LC, | |||
117 | raw_ostream &OS) { | |||
118 | size_t BytesWritten = 0; | |||
119 | for (const auto &Sec : LC.Sections) { | |||
120 | auto TempSec = constructSection<MachO::section>(Sec); | |||
121 | OS.write(reinterpret_cast<const char *>(&(TempSec)), | |||
122 | sizeof(MachO::section)); | |||
123 | BytesWritten += sizeof(MachO::section); | |||
124 | } | |||
125 | return BytesWritten; | |||
126 | } | |||
127 | ||||
128 | template <> | |||
129 | size_t | |||
130 | writeLoadCommandData<MachO::segment_command_64>(MachOYAML::LoadCommand &LC, | |||
131 | raw_ostream &OS) { | |||
132 | size_t BytesWritten = 0; | |||
133 | for (const auto &Sec : LC.Sections) { | |||
134 | auto TempSec = constructSection<MachO::section_64>(Sec); | |||
135 | TempSec.reserved3 = Sec.reserved3; | |||
136 | OS.write(reinterpret_cast<const char *>(&(TempSec)), | |||
137 | sizeof(MachO::section_64)); | |||
138 | BytesWritten += sizeof(MachO::section_64); | |||
139 | } | |||
140 | return BytesWritten; | |||
141 | } | |||
142 | ||||
143 | size_t writePayloadString(MachOYAML::LoadCommand &LC, raw_ostream &OS) { | |||
144 | size_t BytesWritten = 0; | |||
145 | if (!LC.PayloadString.empty()) { | |||
146 | OS.write(LC.PayloadString.c_str(), LC.PayloadString.length()); | |||
147 | BytesWritten = LC.PayloadString.length(); | |||
148 | } | |||
149 | return BytesWritten; | |||
150 | } | |||
151 | ||||
152 | template <> | |||
153 | size_t writeLoadCommandData<MachO::dylib_command>(MachOYAML::LoadCommand &LC, | |||
154 | raw_ostream &OS) { | |||
155 | return writePayloadString(LC, OS); | |||
156 | } | |||
157 | ||||
158 | template <> | |||
159 | size_t writeLoadCommandData<MachO::dylinker_command>(MachOYAML::LoadCommand &LC, | |||
160 | raw_ostream &OS) { | |||
161 | return writePayloadString(LC, OS); | |||
162 | } | |||
163 | ||||
164 | void ZeroFillBytes(raw_ostream &OS, size_t Size) { | |||
165 | std::vector<uint8_t> FillData; | |||
166 | FillData.insert(FillData.begin(), Size, 0); | |||
167 | OS.write(reinterpret_cast<char *>(FillData.data()), Size); | |||
168 | } | |||
169 | ||||
170 | void Fill(raw_ostream &OS, size_t Size, uint32_t Data) { | |||
171 | std::vector<uint32_t> FillData; | |||
172 | FillData.insert(FillData.begin(), (Size / 4) + 1, Data); | |||
173 | OS.write(reinterpret_cast<char *>(FillData.data()), Size); | |||
174 | } | |||
175 | ||||
176 | void MachOWriter::ZeroToOffset(raw_ostream &OS, size_t Offset) { | |||
177 | auto currOffset = OS.tell() - fileStart; | |||
178 | if (currOffset < Offset) | |||
179 | ZeroFillBytes(OS, Offset - currOffset); | |||
180 | } | |||
181 | ||||
182 | Error MachOWriter::writeLoadCommands(raw_ostream &OS) { | |||
183 | for (auto &LC : Obj.LoadCommands) { | |||
184 | size_t BytesWritten = 0; | |||
185 | #define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \ | |||
186 | case MachO::LCName: \ | |||
187 | OS.write(reinterpret_cast<const char *>(&(LC.Data.LCStruct##_data)), \ | |||
188 | sizeof(MachO::LCStruct)); \ | |||
189 | BytesWritten = sizeof(MachO::LCStruct); \ | |||
190 | BytesWritten += writeLoadCommandData<MachO::LCStruct>(LC, OS); \ | |||
191 | break; | |||
192 | ||||
193 | switch (LC.Data.load_command_data.cmd) { | |||
194 | default: | |||
195 | OS.write(reinterpret_cast<const char *>(&(LC.Data.load_command_data)), | |||
196 | sizeof(MachO::load_command)); | |||
197 | BytesWritten = sizeof(MachO::load_command); | |||
198 | BytesWritten += writeLoadCommandData<MachO::load_command>(LC, OS); | |||
199 | break; | |||
200 | #include "llvm/Support/MachO.def" | |||
201 | } | |||
202 | ||||
203 | if (LC.PayloadBytes.size() > 0) { | |||
204 | OS.write(reinterpret_cast<const char *>(LC.PayloadBytes.data()), | |||
205 | LC.PayloadBytes.size()); | |||
206 | BytesWritten += LC.PayloadBytes.size(); | |||
207 | } | |||
208 | ||||
209 | if (LC.ZeroPadBytes > 0) { | |||
210 | ZeroFillBytes(OS, LC.ZeroPadBytes); | |||
211 | BytesWritten += LC.ZeroPadBytes; | |||
212 | } | |||
213 | ||||
214 | // Fill remaining bytes with 0. This will only get hit in partially | |||
215 | // specified test cases. | |||
216 | auto BytesRemaining = LC.Data.load_command_data.cmdsize - BytesWritten; | |||
217 | if (BytesRemaining > 0) { | |||
218 | ZeroFillBytes(OS, BytesRemaining); | |||
219 | } | |||
220 | } | |||
221 | return Error::success(); | |||
222 | } | |||
223 | ||||
224 | Error MachOWriter::writeSectionData(raw_ostream &OS) { | |||
225 | for (auto &LC : Obj.LoadCommands) { | |||
226 | switch (LC.Data.load_command_data.cmd) { | |||
227 | case MachO::LC_SEGMENT: | |||
228 | case MachO::LC_SEGMENT_64: | |||
229 | auto currOffset = OS.tell() - fileStart; | |||
230 | auto segname = LC.Data.segment_command_data.segname; | |||
231 | uint64_t segOff = is64Bit ? LC.Data.segment_command_64_data.fileoff | |||
232 | : LC.Data.segment_command_data.fileoff; | |||
233 | ||||
234 | if (0 == strncmp(&segname[0], "__LINKEDIT", 16)) { | |||
235 | if (auto Err = writeLinkEditData(OS)) | |||
236 | return Err; | |||
237 | } else { | |||
238 | // Zero Fill any data between the end of the last thing we wrote and the | |||
239 | // start of this section. | |||
240 | if (currOffset < segOff) { | |||
241 | ZeroFillBytes(OS, segOff - currOffset); | |||
242 | } | |||
243 | ||||
244 | for (auto &Sec : LC.Sections) { | |||
245 | // Zero Fill any data between the end of the last thing we wrote and | |||
246 | // the | |||
247 | // start of this section. | |||
248 | assert(((OS.tell() - fileStart <= Sec.offset && "Wrote too much data somewhere, section offsets don't line up." ) ? static_cast<void> (0) : __assert_fail ("OS.tell() - fileStart <= Sec.offset && \"Wrote too much data somewhere, section offsets don't line up.\"" , "/tmp/buildd/llvm-toolchain-snapshot-3.9~svn271203/tools/yaml2obj/yaml2macho.cpp" , 250, __PRETTY_FUNCTION__)) | |||
249 | OS.tell() - fileStart <= Sec.offset &&((OS.tell() - fileStart <= Sec.offset && "Wrote too much data somewhere, section offsets don't line up." ) ? static_cast<void> (0) : __assert_fail ("OS.tell() - fileStart <= Sec.offset && \"Wrote too much data somewhere, section offsets don't line up.\"" , "/tmp/buildd/llvm-toolchain-snapshot-3.9~svn271203/tools/yaml2obj/yaml2macho.cpp" , 250, __PRETTY_FUNCTION__)) | |||
250 | "Wrote too much data somewhere, section offsets don't line up.")((OS.tell() - fileStart <= Sec.offset && "Wrote too much data somewhere, section offsets don't line up." ) ? static_cast<void> (0) : __assert_fail ("OS.tell() - fileStart <= Sec.offset && \"Wrote too much data somewhere, section offsets don't line up.\"" , "/tmp/buildd/llvm-toolchain-snapshot-3.9~svn271203/tools/yaml2obj/yaml2macho.cpp" , 250, __PRETTY_FUNCTION__)); | |||
251 | currOffset = OS.tell() - fileStart; | |||
252 | if (currOffset < Sec.offset) { | |||
253 | ZeroFillBytes(OS, Sec.offset - currOffset); | |||
254 | } | |||
255 | ||||
256 | // Fills section data with 0xDEADBEEF | |||
257 | Fill(OS, Sec.size, 0xDEADBEEFu); | |||
258 | } | |||
259 | } | |||
260 | uint64_t segSize = is64Bit ? LC.Data.segment_command_64_data.filesize | |||
261 | : LC.Data.segment_command_data.filesize; | |||
262 | ZeroToOffset(OS, segOff + segSize); | |||
263 | break; | |||
264 | } | |||
265 | } | |||
266 | return Error::success(); | |||
267 | } | |||
268 | ||||
269 | void MachOWriter::writeBindOpcodes( | |||
270 | raw_ostream &OS, uint64_t offset, | |||
271 | std::vector<MachOYAML::BindOpcode> &BindOpcodes) { | |||
272 | ZeroToOffset(OS, offset); | |||
273 | ||||
274 | for (auto Opcode : BindOpcodes) { | |||
275 | uint8_t OpByte = Opcode.Opcode | Opcode.Imm; | |||
276 | OS.write(reinterpret_cast<char *>(&OpByte), 1); | |||
277 | for (auto Data : Opcode.ULEBExtraData) { | |||
278 | encodeULEB128(Data, OS); | |||
279 | } | |||
280 | for (auto Data : Opcode.SLEBExtraData) { | |||
281 | encodeSLEB128(Data, OS); | |||
282 | } | |||
283 | if (!Opcode.Symbol.empty()) { | |||
284 | OS.write(Opcode.Symbol.data(), Opcode.Symbol.size()); | |||
285 | OS.write("\0", 1); | |||
286 | } | |||
287 | } | |||
288 | } | |||
289 | ||||
290 | Error MachOWriter::writeLinkEditData(raw_ostream &OS) { | |||
291 | MachOYAML::LinkEditData &LinkEdit = Obj.LinkEdit; | |||
292 | MachO::dyld_info_command *DyldInfoOnlyCmd = 0; | |||
293 | MachO::symtab_command *SymtabCmd = 0; | |||
| ||||
294 | for (auto &LC : Obj.LoadCommands) { | |||
295 | switch (LC.Data.load_command_data.cmd) { | |||
296 | case MachO::LC_SYMTAB: | |||
297 | SymtabCmd = &LC.Data.symtab_command_data; | |||
298 | break; | |||
299 | case MachO::LC_DYLD_INFO_ONLY: | |||
300 | DyldInfoOnlyCmd = &LC.Data.dyld_info_command_data; | |||
301 | break; | |||
302 | } | |||
303 | } | |||
304 | ||||
305 | ZeroToOffset(OS, DyldInfoOnlyCmd->rebase_off); | |||
306 | ||||
307 | for (auto Opcode : LinkEdit.RebaseOpcodes) { | |||
308 | uint8_t OpByte = Opcode.Opcode | Opcode.Imm; | |||
309 | OS.write(reinterpret_cast<char *>(&OpByte), 1); | |||
310 | for (auto Data : Opcode.ExtraData) { | |||
311 | encodeULEB128(Data, OS); | |||
312 | } | |||
313 | } | |||
314 | ||||
315 | writeBindOpcodes(OS, DyldInfoOnlyCmd->bind_off, LinkEdit.BindOpcodes); | |||
316 | writeBindOpcodes(OS, DyldInfoOnlyCmd->weak_bind_off, | |||
317 | LinkEdit.WeakBindOpcodes); | |||
318 | writeBindOpcodes(OS, DyldInfoOnlyCmd->lazy_bind_off, | |||
319 | LinkEdit.LazyBindOpcodes); | |||
320 | ||||
321 | // Fill to the end of the string table | |||
322 | ZeroToOffset(OS, SymtabCmd->stroff + SymtabCmd->strsize); | |||
| ||||
323 | ||||
324 | return Error::success(); | |||
325 | } | |||
326 | ||||
327 | } // end anonymous namespace | |||
328 | ||||
329 | int yaml2macho(yaml::Input &YIn, raw_ostream &Out) { | |||
330 | MachOYAML::Object Doc; | |||
331 | YIn >> Doc; | |||
332 | if (YIn.error()) { | |||
333 | errs() << "yaml2obj: Failed to parse YAML file!\n"; | |||
334 | return 1; | |||
335 | } | |||
336 | ||||
337 | MachOWriter Writer(Doc); | |||
338 | if (auto Err = Writer.writeMachO(Out)) { | |||
339 | errs() << toString(std::move(Err)); | |||
340 | return 1; | |||
341 | } | |||
342 | return 0; | |||
343 | } |