1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | #include "clang/Basic/Diagnostic.h" |
16 | #include "clang/Basic/DiagnosticOptions.h" |
17 | #include "clang/Driver/Arg.h" |
18 | #include "clang/Driver/ArgList.h" |
19 | #include "clang/Driver/CC1AsOptions.h" |
20 | #include "clang/Driver/DriverDiagnostic.h" |
21 | #include "clang/Driver/OptTable.h" |
22 | #include "clang/Driver/Options.h" |
23 | #include "clang/Frontend/FrontendDiagnostic.h" |
24 | #include "clang/Frontend/TextDiagnosticPrinter.h" |
25 | #include "llvm/ADT/OwningPtr.h" |
26 | #include "llvm/ADT/StringSwitch.h" |
27 | #include "llvm/ADT/Triple.h" |
28 | #include "llvm/IR/DataLayout.h" |
29 | #include "llvm/MC/MCAsmBackend.h" |
30 | #include "llvm/MC/MCAsmInfo.h" |
31 | #include "llvm/MC/MCCodeEmitter.h" |
32 | #include "llvm/MC/MCContext.h" |
33 | #include "llvm/MC/MCInstrInfo.h" |
34 | #include "llvm/MC/MCObjectFileInfo.h" |
35 | #include "llvm/MC/MCParser/MCAsmParser.h" |
36 | #include "llvm/MC/MCRegisterInfo.h" |
37 | #include "llvm/MC/MCStreamer.h" |
38 | #include "llvm/MC/MCSubtargetInfo.h" |
39 | #include "llvm/MC/MCTargetAsmParser.h" |
40 | #include "llvm/Support/CommandLine.h" |
41 | #include "llvm/Support/ErrorHandling.h" |
42 | #include "llvm/Support/FormattedStream.h" |
43 | #include "llvm/Support/Host.h" |
44 | #include "llvm/Support/ManagedStatic.h" |
45 | #include "llvm/Support/MemoryBuffer.h" |
46 | #include "llvm/Support/Path.h" |
47 | #include "llvm/Support/PrettyStackTrace.h" |
48 | #include "llvm/Support/Signals.h" |
49 | #include "llvm/Support/SourceMgr.h" |
50 | #include "llvm/Support/TargetRegistry.h" |
51 | #include "llvm/Support/TargetSelect.h" |
52 | #include "llvm/Support/Timer.h" |
53 | #include "llvm/Support/raw_ostream.h" |
54 | #include "llvm/Support/system_error.h" |
55 | using namespace clang; |
56 | using namespace clang::driver; |
57 | using namespace llvm; |
58 | |
59 | namespace { |
60 | |
61 | |
62 | struct AssemblerInvocation { |
63 | |
64 | |
65 | |
66 | |
67 | std::string Triple; |
68 | |
69 | |
70 | |
71 | std::string CPU; |
72 | |
73 | |
74 | |
75 | std::vector<std::string> Features; |
76 | |
77 | |
78 | |
79 | |
80 | |
81 | std::vector<std::string> IncludePaths; |
82 | unsigned NoInitialTextSection : 1; |
83 | unsigned SaveTemporaryLabels : 1; |
84 | unsigned GenDwarfForAssembly : 1; |
85 | std::string DwarfDebugFlags; |
86 | std::string DwarfDebugProducer; |
87 | std::string DebugCompilationDir; |
88 | std::string MainFileName; |
89 | |
90 | |
91 | |
92 | |
93 | |
94 | std::string InputFile; |
95 | std::vector<std::string> LLVMArgs; |
96 | std::string OutputPath; |
97 | enum FileType { |
98 | FT_Asm, |
99 | FT_Null, |
100 | FT_Obj |
101 | }; |
102 | FileType OutputType; |
103 | unsigned ShowHelp : 1; |
104 | unsigned ShowVersion : 1; |
105 | |
106 | |
107 | |
108 | |
109 | |
110 | unsigned OutputAsmVariant; |
111 | unsigned ShowEncoding : 1; |
112 | unsigned ShowInst : 1; |
113 | |
114 | |
115 | |
116 | |
117 | |
118 | unsigned RelaxAll : 1; |
119 | unsigned NoExecStack : 1; |
120 | |
121 | |
122 | |
123 | public: |
124 | AssemblerInvocation() { |
125 | Triple = ""; |
126 | NoInitialTextSection = 0; |
127 | InputFile = "-"; |
128 | OutputPath = "-"; |
129 | OutputType = FT_Asm; |
130 | OutputAsmVariant = 0; |
131 | ShowInst = 0; |
132 | ShowEncoding = 0; |
133 | RelaxAll = 0; |
134 | NoExecStack = 0; |
135 | } |
136 | |
137 | static bool CreateFromArgs(AssemblerInvocation &Res, const char **ArgBegin, |
138 | const char **ArgEnd, DiagnosticsEngine &Diags); |
139 | }; |
140 | |
141 | } |
142 | |
143 | bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts, |
144 | const char **ArgBegin, |
145 | const char **ArgEnd, |
146 | DiagnosticsEngine &Diags) { |
147 | using namespace clang::driver::cc1asoptions; |
148 | bool Success = true; |
149 | |
150 | |
151 | OwningPtr<OptTable> OptTbl(createCC1AsOptTable()); |
152 | unsigned MissingArgIndex, MissingArgCount; |
153 | OwningPtr<InputArgList> Args( |
154 | OptTbl->ParseArgs(ArgBegin, ArgEnd,MissingArgIndex, MissingArgCount)); |
155 | |
156 | |
157 | if (MissingArgCount) { |
158 | Diags.Report(diag::err_drv_missing_argument) |
159 | << Args->getArgString(MissingArgIndex) << MissingArgCount; |
160 | Success = false; |
161 | } |
162 | |
163 | |
164 | for (arg_iterator it = Args->filtered_begin(cc1asoptions::OPT_UNKNOWN), |
165 | ie = Args->filtered_end(); it != ie; ++it) { |
166 | Diags.Report(diag::err_drv_unknown_argument) << (*it) ->getAsString(*Args); |
167 | Success = false; |
168 | } |
169 | |
170 | |
171 | |
172 | |
173 | Opts.Triple = llvm::Triple::normalize(Args->getLastArgValue(OPT_triple)); |
174 | Opts.CPU = Args->getLastArgValue(OPT_target_cpu); |
175 | Opts.Features = Args->getAllArgValues(OPT_target_feature); |
176 | |
177 | |
178 | if (Opts.Triple.empty()) |
179 | Opts.Triple = llvm::sys::getDefaultTargetTriple(); |
180 | |
181 | |
182 | Opts.IncludePaths = Args->getAllArgValues(OPT_I); |
183 | Opts.NoInitialTextSection = Args->hasArg(OPT_n); |
184 | Opts.SaveTemporaryLabels = Args->hasArg(OPT_L); |
185 | Opts.GenDwarfForAssembly = Args->hasArg(OPT_g); |
186 | Opts.DwarfDebugFlags = Args->getLastArgValue(OPT_dwarf_debug_flags); |
187 | Opts.DwarfDebugProducer = Args->getLastArgValue(OPT_dwarf_debug_producer); |
188 | Opts.DebugCompilationDir = Args->getLastArgValue(OPT_fdebug_compilation_dir); |
189 | Opts.MainFileName = Args->getLastArgValue(OPT_main_file_name); |
190 | |
191 | |
192 | if (Args->hasArg(OPT_INPUT)) { |
193 | bool First = true; |
194 | for (arg_iterator it = Args->filtered_begin(OPT_INPUT), |
195 | ie = Args->filtered_end(); it != ie; ++it, First=false) { |
196 | const Arg *A = it; |
197 | if (First) |
198 | Opts.InputFile = A->getValue(); |
199 | else { |
200 | Diags.Report(diag::err_drv_unknown_argument) << A->getAsString(*Args); |
201 | Success = false; |
202 | } |
203 | } |
204 | } |
205 | Opts.LLVMArgs = Args->getAllArgValues(OPT_mllvm); |
206 | if (Args->hasArg(OPT_fatal_warnings)) |
207 | Opts.LLVMArgs.push_back("-fatal-assembler-warnings"); |
208 | Opts.OutputPath = Args->getLastArgValue(OPT_o); |
209 | if (Arg *A = Args->getLastArg(OPT_filetype)) { |
210 | StringRef Name = A->getValue(); |
211 | unsigned OutputType = StringSwitch<unsigned>(Name) |
212 | .Case("asm", FT_Asm) |
213 | .Case("null", FT_Null) |
214 | .Case("obj", FT_Obj) |
215 | .Default(~0U); |
216 | if (OutputType == ~0U) { |
217 | Diags.Report(diag::err_drv_invalid_value) |
218 | << A->getAsString(*Args) << Name; |
219 | Success = false; |
220 | } else |
221 | Opts.OutputType = FileType(OutputType); |
222 | } |
223 | Opts.ShowHelp = Args->hasArg(OPT_help); |
224 | Opts.ShowVersion = Args->hasArg(OPT_version); |
225 | |
226 | |
227 | Opts.OutputAsmVariant = Args->getLastArgIntValue(OPT_output_asm_variant, |
228 | 0, Diags); |
229 | Opts.ShowEncoding = Args->hasArg(OPT_show_encoding); |
230 | Opts.ShowInst = Args->hasArg(OPT_show_inst); |
231 | |
232 | |
233 | Opts.RelaxAll = Args->hasArg(OPT_relax_all); |
234 | Opts.NoExecStack = Args->hasArg(OPT_no_exec_stack); |
235 | |
236 | return Success; |
237 | } |
238 | |
239 | static formatted_raw_ostream *GetOutputStream(AssemblerInvocation &Opts, |
240 | DiagnosticsEngine &Diags, |
241 | bool Binary) { |
242 | if (Opts.OutputPath.empty()) |
| |
243 | Opts.OutputPath = "-"; |
244 | |
245 | |
246 | |
247 | if (Opts.OutputPath != "-") |
| |
248 | sys::RemoveFileOnSignal(sys::Path(Opts.OutputPath)); |
249 | |
250 | std::string Error; |
251 | raw_fd_ostream *Out = |
252 | new raw_fd_ostream(Opts.OutputPath.c_str(), Error, |
253 | (Binary ? raw_fd_ostream::F_Binary : 0)); |
| |
254 | if (!Error.empty()) { |
| |
255 | Diags.Report(diag::err_fe_unable_to_open_output) |
256 | << Opts.OutputPath << Error; |
257 | return 0; |
258 | } |
259 | |
260 | return new formatted_raw_ostream(*Out, formatted_raw_ostream::DELETE_STREAM); |
| |
261 | } |
262 | |
263 | static bool ExecuteAssembler(AssemblerInvocation &Opts, |
264 | DiagnosticsEngine &Diags) { |
265 | |
266 | std::string Error; |
267 | const Target *TheTarget(TargetRegistry::lookupTarget(Opts.Triple, Error)); |
268 | if (!TheTarget) { |
| 7 | | Assuming 'TheTarget' is non-null | |
|
| |
269 | Diags.Report(diag::err_target_unknown_triple) << Opts.Triple; |
270 | return false; |
271 | } |
272 | |
273 | OwningPtr<MemoryBuffer> BufferPtr; |
274 | if (error_code ec = MemoryBuffer::getFileOrSTDIN(Opts.InputFile, BufferPtr)) { |
| |
275 | Error = ec.message(); |
276 | Diags.Report(diag::err_fe_error_reading) << Opts.InputFile; |
277 | return false; |
278 | } |
279 | MemoryBuffer *Buffer = BufferPtr.take(); |
280 | |
281 | SourceMgr SrcMgr; |
282 | |
283 | |
284 | SrcMgr.AddNewSourceBuffer(Buffer, SMLoc()); |
285 | |
286 | |
287 | |
288 | SrcMgr.setIncludeDirs(Opts.IncludePaths); |
289 | |
290 | OwningPtr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(Opts.Triple)); |
291 | assert(MAI && "Unable to create target asm info!")((void)0); |
292 | |
293 | OwningPtr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(Opts.Triple)); |
294 | assert(MRI && "Unable to create target register info!")((void)0); |
295 | |
296 | bool IsBinary = Opts.OutputType == AssemblerInvocation::FT_Obj; |
297 | formatted_raw_ostream *Out = GetOutputStream(Opts, Diags, IsBinary); |
| 10 | | Calling 'GetOutputStream' | |
|
| 16 | | Returned allocated memory | |
|
298 | if (!Out) |
| |
299 | return false; |
300 | |
301 | |
302 | |
303 | OwningPtr<MCObjectFileInfo> MOFI(new MCObjectFileInfo()); |
304 | MCContext Ctx(*MAI, *MRI, MOFI.get(), &SrcMgr); |
305 | |
306 | MOFI->InitMCObjectFileInfo(Opts.Triple, |
307 | Reloc::Default, CodeModel::Default, Ctx); |
308 | if (Opts.SaveTemporaryLabels) |
| |
309 | Ctx.setAllowTemporaryLabels(false); |
310 | if (Opts.GenDwarfForAssembly) |
| |
311 | Ctx.setGenDwarfForAssembly(true); |
312 | if (!Opts.DwarfDebugFlags.empty()) |
| |
313 | Ctx.setDwarfDebugFlags(StringRef(Opts.DwarfDebugFlags)); |
314 | if (!Opts.DwarfDebugProducer.empty()) |
| |
315 | Ctx.setDwarfDebugProducer(StringRef(Opts.DwarfDebugProducer)); |
316 | if (!Opts.DebugCompilationDir.empty()) |
| |
317 | Ctx.setCompilationDir(Opts.DebugCompilationDir); |
318 | if (!Opts.MainFileName.empty()) |
| |
319 | Ctx.setMainFileName(StringRef(Opts.MainFileName)); |
320 | |
321 | |
322 | std::string FS; |
323 | if (!Opts.Features.empty()) { |
| |
324 | FS = Opts.Features[0]; |
325 | for (unsigned i = 1, e = Opts.Features.size(); i != e; ++i) |
326 | FS += "," + Opts.Features[i]; |
327 | } |
328 | |
329 | OwningPtr<MCStreamer> Str; |
330 | |
331 | OwningPtr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo()); |
332 | OwningPtr<MCSubtargetInfo> |
333 | STI(TheTarget->createMCSubtargetInfo(Opts.Triple, Opts.CPU, FS)); |
334 | |
335 | |
336 | if (Opts.OutputType == AssemblerInvocation::FT_Asm) { |
| |
337 | MCInstPrinter *IP = |
338 | TheTarget->createMCInstPrinter(Opts.OutputAsmVariant, *MAI, *MCII, *MRI, |
339 | *STI); |
340 | MCCodeEmitter *CE = 0; |
341 | MCAsmBackend *MAB = 0; |
342 | if (Opts.ShowEncoding) { |
343 | CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, *STI, Ctx); |
344 | MAB = TheTarget->createMCAsmBackend(Opts.Triple, Opts.CPU); |
345 | } |
346 | Str.reset(TheTarget->createAsmStreamer(Ctx, *Out, true, |
347 | true, |
348 | true, |
349 | true, |
350 | IP, CE, MAB, |
351 | Opts.ShowInst)); |
352 | } else if (Opts.OutputType == AssemblerInvocation::FT_Null) { |
| |
353 | Str.reset(createNullStreamer(Ctx)); |
354 | } else { |
355 | assert(Opts.OutputType == AssemblerInvocation::FT_Obj &&((void)0) |
356 | "Invalid file type!")((void)0); |
357 | MCCodeEmitter *CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, *STI, Ctx); |
358 | MCAsmBackend *MAB = TheTarget->createMCAsmBackend(Opts.Triple, Opts.CPU); |
359 | Str.reset(TheTarget->createMCObjectStreamer(Opts.Triple, Ctx, *MAB, *Out, |
360 | CE, Opts.RelaxAll, |
361 | Opts.NoExecStack)); |
362 | Str.get()->InitSections(); |
363 | } |
364 | |
365 | OwningPtr<MCAsmParser> Parser(createMCAsmParser(SrcMgr, Ctx, |
366 | *Str.get(), *MAI)); |
367 | OwningPtr<MCTargetAsmParser> TAP(TheTarget->createMCAsmParser(*STI, *Parser)); |
368 | if (!TAP) { |
| |
369 | Diags.Report(diag::err_target_unknown_triple) << Opts.Triple; |
| 28 | | Memory is never released; potential leak of memory pointed to by 'Out' |
|
370 | return false; |
371 | } |
372 | |
373 | Parser->setTargetParser(*TAP.get()); |
374 | |
375 | bool Success = !Parser->Run(Opts.NoInitialTextSection); |
376 | |
377 | |
378 | delete Out; |
379 | |
380 | |
381 | if (!Success && Opts.OutputPath != "-") |
382 | sys::Path(Opts.OutputPath).eraseFromDisk(); |
383 | |
384 | return Success; |
385 | } |
386 | |
387 | static void LLVMErrorHandler(void *UserData, const std::string &Message) { |
388 | DiagnosticsEngine &Diags = *static_cast<DiagnosticsEngine*>(UserData); |
389 | |
390 | Diags.Report(diag::err_fe_error_backend) << Message; |
391 | |
392 | |
393 | exit(1); |
394 | } |
395 | |
396 | int cc1as_main(const char **ArgBegin, const char **ArgEnd, |
397 | const char *Argv0, void *MainAddr) { |
398 | |
399 | sys::PrintStackTraceOnErrorSignal(); |
400 | PrettyStackTraceProgram X(ArgEnd - ArgBegin, ArgBegin); |
401 | llvm_shutdown_obj Y; |
402 | |
403 | |
404 | InitializeAllTargetInfos(); |
405 | InitializeAllTargetMCs(); |
406 | InitializeAllAsmParsers(); |
407 | |
408 | |
409 | IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); |
410 | TextDiagnosticPrinter *DiagClient |
411 | = new TextDiagnosticPrinter(errs(), &*DiagOpts); |
412 | DiagClient->setPrefix("clang -cc1as"); |
413 | IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); |
414 | DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient); |
415 | |
416 | |
417 | |
418 | ScopedFatalErrorHandler FatalErrorHandler |
419 | (LLVMErrorHandler, static_cast<void*>(&Diags)); |
420 | |
421 | |
422 | AssemblerInvocation Asm; |
423 | if (!AssemblerInvocation::CreateFromArgs(Asm, ArgBegin, ArgEnd, Diags)) |
| |
424 | return 1; |
425 | |
426 | |
427 | if (Asm.ShowHelp) { |
| |
428 | OwningPtr<driver::OptTable> Opts(driver::createCC1AsOptTable()); |
429 | Opts->PrintHelp(llvm::outs(), "clang -cc1as", "Clang Integrated Assembler"); |
430 | return 0; |
431 | } |
432 | |
433 | |
434 | |
435 | |
436 | if (Asm.ShowVersion) { |
| |
437 | llvm::cl::PrintVersionMessage(); |
438 | return 0; |
439 | } |
440 | |
441 | |
442 | |
443 | |
444 | if (!Asm.LLVMArgs.empty()) { |
| |
445 | unsigned NumArgs = Asm.LLVMArgs.size(); |
446 | const char **Args = new const char*[NumArgs + 2]; |
447 | Args[0] = "clang (LLVM option parsing)"; |
448 | for (unsigned i = 0; i != NumArgs; ++i) |
449 | Args[i + 1] = Asm.LLVMArgs[i].c_str(); |
450 | Args[NumArgs + 1] = 0; |
451 | llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args); |
452 | } |
453 | |
454 | |
455 | bool Success = false; |
456 | if (!Diags.hasErrorOccurred()) |
| |
457 | Success = ExecuteAssembler(Asm, Diags); |
| 6 | | Calling 'ExecuteAssembler' | |
|
458 | |
459 | |
460 | |
461 | TimerGroup::printAll(errs()); |
462 | |
463 | return !Success; |
464 | } |