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