1 | //===-- llvm-mc.cpp - Machine Code Hacking Driver ---------------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This utility is a simple driver that allows command line hacking on machine |
10 | // code. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "Disassembler.h" |
15 | #include "llvm/MC/MCAsmBackend.h" |
16 | #include "llvm/MC/MCAsmInfo.h" |
17 | #include "llvm/MC/MCCodeEmitter.h" |
18 | #include "llvm/MC/MCContext.h" |
19 | #include "llvm/MC/MCInstPrinter.h" |
20 | #include "llvm/MC/MCInstrInfo.h" |
21 | #include "llvm/MC/MCObjectFileInfo.h" |
22 | #include "llvm/MC/MCObjectWriter.h" |
23 | #include "llvm/MC/MCParser/AsmLexer.h" |
24 | #include "llvm/MC/MCParser/MCTargetAsmParser.h" |
25 | #include "llvm/MC/MCRegisterInfo.h" |
26 | #include "llvm/MC/MCStreamer.h" |
27 | #include "llvm/MC/MCSubtargetInfo.h" |
28 | #include "llvm/MC/MCTargetOptionsCommandFlags.h" |
29 | #include "llvm/MC/TargetRegistry.h" |
30 | #include "llvm/Support/CommandLine.h" |
31 | #include "llvm/Support/Compression.h" |
32 | #include "llvm/Support/FileUtilities.h" |
33 | #include "llvm/Support/FormattedStream.h" |
34 | #include "llvm/Support/InitLLVM.h" |
35 | #include "llvm/Support/MemoryBuffer.h" |
36 | #include "llvm/Support/SourceMgr.h" |
37 | #include "llvm/Support/TargetSelect.h" |
38 | #include "llvm/Support/ToolOutputFile.h" |
39 | #include "llvm/Support/WithColor.h" |
40 | #include "llvm/TargetParser/Host.h" |
41 | |
42 | using namespace llvm; |
43 | |
44 | static mc::RegisterMCTargetOptionsFlags MOF; |
45 | |
46 | static cl::OptionCategory MCCategory("MC Options" ); |
47 | |
48 | static cl::opt<std::string> InputFilename(cl::Positional, |
49 | cl::desc("<input file>" ), |
50 | cl::init(Val: "-" ), cl::cat(MCCategory)); |
51 | |
52 | static cl::list<std::string> InstPrinterOptions("M" , |
53 | cl::desc("InstPrinter options" ), |
54 | cl::cat(MCCategory)); |
55 | |
56 | static cl::opt<std::string> OutputFilename("o" , cl::desc("Output filename" ), |
57 | cl::value_desc("filename" ), |
58 | cl::init(Val: "-" ), cl::cat(MCCategory)); |
59 | |
60 | static cl::opt<std::string> SplitDwarfFile("split-dwarf-file" , |
61 | cl::desc("DWO output filename" ), |
62 | cl::value_desc("filename" ), |
63 | cl::cat(MCCategory)); |
64 | |
65 | static cl::opt<bool> ShowEncoding("show-encoding" , |
66 | cl::desc("Show instruction encodings" ), |
67 | cl::cat(MCCategory)); |
68 | |
69 | static cl::opt<DebugCompressionType> CompressDebugSections( |
70 | "compress-debug-sections" , cl::ValueOptional, |
71 | cl::init(Val: DebugCompressionType::None), |
72 | cl::desc("Choose DWARF debug sections compression:" ), |
73 | cl::values(clEnumValN(DebugCompressionType::None, "none" , "No compression" ), |
74 | clEnumValN(DebugCompressionType::Zlib, "zlib" , "Use zlib" ), |
75 | clEnumValN(DebugCompressionType::Zstd, "zstd" , "Use zstd" )), |
76 | cl::cat(MCCategory)); |
77 | |
78 | static cl::opt<bool> |
79 | ShowInst("show-inst" , cl::desc("Show internal instruction representation" ), |
80 | cl::cat(MCCategory)); |
81 | |
82 | static cl::opt<bool> |
83 | ShowInstOperands("show-inst-operands" , |
84 | cl::desc("Show instructions operands as parsed" ), |
85 | cl::cat(MCCategory)); |
86 | |
87 | static cl::opt<unsigned> |
88 | OutputAsmVariant("output-asm-variant" , |
89 | cl::desc("Syntax variant to use for output printing" ), |
90 | cl::cat(MCCategory)); |
91 | |
92 | static cl::opt<bool> |
93 | PrintImmHex("print-imm-hex" , cl::init(Val: false), |
94 | cl::desc("Prefer hex format for immediate values" ), |
95 | cl::cat(MCCategory)); |
96 | |
97 | static cl::opt<bool> |
98 | HexBytes("hex" , |
99 | cl::desc("Take raw hexadecimal bytes as input for disassembly. " |
100 | "Whitespace is ignored" ), |
101 | cl::cat(MCCategory)); |
102 | |
103 | static cl::list<std::string> |
104 | DefineSymbol("defsym" , |
105 | cl::desc("Defines a symbol to be an integer constant" ), |
106 | cl::cat(MCCategory)); |
107 | |
108 | static cl::opt<bool> |
109 | ("preserve-comments" , |
110 | cl::desc("Preserve Comments in outputted assembly" ), |
111 | cl::cat(MCCategory)); |
112 | |
113 | static cl::opt<unsigned> CommentColumn("comment-column" , |
114 | cl::desc("Asm comments indentation" ), |
115 | cl::init(Val: 40)); |
116 | |
117 | enum OutputFileType { |
118 | OFT_Null, |
119 | OFT_AssemblyFile, |
120 | OFT_ObjectFile |
121 | }; |
122 | static cl::opt<OutputFileType> |
123 | FileType("filetype" , cl::init(Val: OFT_AssemblyFile), |
124 | cl::desc("Choose an output file type:" ), |
125 | cl::values(clEnumValN(OFT_AssemblyFile, "asm" , |
126 | "Emit an assembly ('.s') file" ), |
127 | clEnumValN(OFT_Null, "null" , |
128 | "Don't emit anything (for timing purposes)" ), |
129 | clEnumValN(OFT_ObjectFile, "obj" , |
130 | "Emit a native object ('.o') file" )), |
131 | cl::cat(MCCategory)); |
132 | |
133 | static cl::list<std::string> IncludeDirs("I" , |
134 | cl::desc("Directory of include files" ), |
135 | cl::value_desc("directory" ), |
136 | cl::Prefix, cl::cat(MCCategory)); |
137 | |
138 | static cl::opt<std::string> |
139 | ArchName("arch" , |
140 | cl::desc("Target arch to assemble for, " |
141 | "see -version for available targets" ), |
142 | cl::cat(MCCategory)); |
143 | |
144 | static cl::opt<std::string> |
145 | TripleName("triple" , |
146 | cl::desc("Target triple to assemble for, " |
147 | "see -version for available targets" ), |
148 | cl::cat(MCCategory)); |
149 | |
150 | static cl::opt<std::string> |
151 | MCPU("mcpu" , |
152 | cl::desc("Target a specific cpu type (-mcpu=help for details)" ), |
153 | cl::value_desc("cpu-name" ), cl::init(Val: "" ), cl::cat(MCCategory)); |
154 | |
155 | static cl::list<std::string> |
156 | MAttrs("mattr" , cl::CommaSeparated, |
157 | cl::desc("Target specific attributes (-mattr=help for details)" ), |
158 | cl::value_desc("a1,+a2,-a3,..." ), cl::cat(MCCategory)); |
159 | |
160 | static cl::opt<bool> PIC("position-independent" , |
161 | cl::desc("Position independent" ), cl::init(Val: false), |
162 | cl::cat(MCCategory)); |
163 | |
164 | static cl::opt<bool> |
165 | LargeCodeModel("large-code-model" , |
166 | cl::desc("Create cfi directives that assume the code might " |
167 | "be more than 2gb away" ), |
168 | cl::cat(MCCategory)); |
169 | |
170 | static cl::opt<bool> |
171 | NoInitialTextSection("n" , |
172 | cl::desc("Don't assume assembly file starts " |
173 | "in the text section" ), |
174 | cl::cat(MCCategory)); |
175 | |
176 | static cl::opt<bool> |
177 | GenDwarfForAssembly("g" , |
178 | cl::desc("Generate dwarf debugging info for assembly " |
179 | "source files" ), |
180 | cl::cat(MCCategory)); |
181 | |
182 | static cl::opt<std::string> |
183 | DebugCompilationDir("fdebug-compilation-dir" , |
184 | cl::desc("Specifies the debug info's compilation dir" ), |
185 | cl::cat(MCCategory)); |
186 | |
187 | static cl::list<std::string> DebugPrefixMap( |
188 | "fdebug-prefix-map" , cl::desc("Map file source paths in debug info" ), |
189 | cl::value_desc("= separated key-value pairs" ), cl::cat(MCCategory)); |
190 | |
191 | static cl::opt<std::string> MainFileName( |
192 | "main-file-name" , |
193 | cl::desc("Specifies the name we should consider the input file" ), |
194 | cl::cat(MCCategory)); |
195 | |
196 | static cl::opt<bool> LexMasmIntegers( |
197 | "masm-integers" , |
198 | cl::desc("Enable binary and hex masm integers (0b110 and 0ABCh)" ), |
199 | cl::cat(MCCategory)); |
200 | |
201 | static cl::opt<bool> LexMasmHexFloats( |
202 | "masm-hexfloats" , |
203 | cl::desc("Enable MASM-style hex float initializers (3F800000r)" ), |
204 | cl::cat(MCCategory)); |
205 | |
206 | static cl::opt<bool> LexMotorolaIntegers( |
207 | "motorola-integers" , |
208 | cl::desc("Enable binary and hex Motorola integers (%110 and $ABC)" ), |
209 | cl::cat(MCCategory)); |
210 | |
211 | static cl::opt<bool> NoExecStack("no-exec-stack" , |
212 | cl::desc("File doesn't need an exec stack" ), |
213 | cl::cat(MCCategory)); |
214 | |
215 | enum ActionType { |
216 | AC_AsLex, |
217 | AC_Assemble, |
218 | AC_Disassemble, |
219 | AC_MDisassemble, |
220 | AC_CDisassemble, |
221 | }; |
222 | |
223 | static cl::opt<ActionType> Action( |
224 | cl::desc("Action to perform:" ), cl::init(Val: AC_Assemble), |
225 | cl::values(clEnumValN(AC_AsLex, "as-lex" , "Lex tokens from a .s file" ), |
226 | clEnumValN(AC_Assemble, "assemble" , |
227 | "Assemble a .s file (default)" ), |
228 | clEnumValN(AC_Disassemble, "disassemble" , |
229 | "Disassemble strings of hex bytes" ), |
230 | clEnumValN(AC_MDisassemble, "mdis" , |
231 | "Marked up disassembly of strings of hex bytes" ), |
232 | clEnumValN(AC_CDisassemble, "cdis" , |
233 | "Colored disassembly of strings of hex bytes" )), |
234 | cl::cat(MCCategory)); |
235 | |
236 | static const Target *GetTarget(const char *ProgName) { |
237 | // Figure out the target triple. |
238 | if (TripleName.empty()) |
239 | TripleName = sys::getDefaultTargetTriple(); |
240 | Triple TheTriple(Triple::normalize(Str: TripleName)); |
241 | |
242 | // Get the target specific parser. |
243 | std::string Error; |
244 | const Target *TheTarget = TargetRegistry::lookupTarget(ArchName, TheTriple, |
245 | Error); |
246 | if (!TheTarget) { |
247 | WithColor::error(OS&: errs(), Prefix: ProgName) << Error; |
248 | return nullptr; |
249 | } |
250 | |
251 | // Update the triple name and return the found target. |
252 | TripleName = TheTriple.getTriple(); |
253 | return TheTarget; |
254 | } |
255 | |
256 | static std::unique_ptr<ToolOutputFile> GetOutputStream(StringRef Path, |
257 | sys::fs::OpenFlags Flags) { |
258 | std::error_code EC; |
259 | auto Out = std::make_unique<ToolOutputFile>(args&: Path, args&: EC, args&: Flags); |
260 | if (EC) { |
261 | WithColor::error() << EC.message() << '\n'; |
262 | return nullptr; |
263 | } |
264 | |
265 | return Out; |
266 | } |
267 | |
268 | static std::string DwarfDebugFlags; |
269 | static void setDwarfDebugFlags(int argc, char **argv) { |
270 | if (!getenv(name: "RC_DEBUG_OPTIONS" )) |
271 | return; |
272 | for (int i = 0; i < argc; i++) { |
273 | DwarfDebugFlags += argv[i]; |
274 | if (i + 1 < argc) |
275 | DwarfDebugFlags += " " ; |
276 | } |
277 | } |
278 | |
279 | static std::string DwarfDebugProducer; |
280 | static void setDwarfDebugProducer() { |
281 | if(!getenv(name: "DEBUG_PRODUCER" )) |
282 | return; |
283 | DwarfDebugProducer += getenv(name: "DEBUG_PRODUCER" ); |
284 | } |
285 | |
286 | static int AsLexInput(SourceMgr &SrcMgr, MCAsmInfo &MAI, |
287 | raw_ostream &OS) { |
288 | |
289 | AsmLexer Lexer(MAI); |
290 | Lexer.setBuffer(Buf: SrcMgr.getMemoryBuffer(i: SrcMgr.getMainFileID())->getBuffer()); |
291 | |
292 | bool Error = false; |
293 | while (Lexer.Lex().isNot(K: AsmToken::Eof)) { |
294 | Lexer.getTok().dump(OS); |
295 | OS << "\n" ; |
296 | if (Lexer.getTok().getKind() == AsmToken::Error) |
297 | Error = true; |
298 | } |
299 | |
300 | return Error; |
301 | } |
302 | |
303 | static int fillCommandLineSymbols(MCAsmParser &Parser) { |
304 | for (auto &I: DefineSymbol) { |
305 | auto Pair = StringRef(I).split(Separator: '='); |
306 | auto Sym = Pair.first; |
307 | auto Val = Pair.second; |
308 | |
309 | if (Sym.empty() || Val.empty()) { |
310 | WithColor::error() << "defsym must be of the form: sym=value: " << I |
311 | << "\n" ; |
312 | return 1; |
313 | } |
314 | int64_t Value; |
315 | if (Val.getAsInteger(Radix: 0, Result&: Value)) { |
316 | WithColor::error() << "value is not an integer: " << Val << "\n" ; |
317 | return 1; |
318 | } |
319 | Parser.getContext().setSymbolValue(Streamer&: Parser.getStreamer(), Sym, Val: Value); |
320 | } |
321 | return 0; |
322 | } |
323 | |
324 | static int AssembleInput(const char *ProgName, const Target *TheTarget, |
325 | SourceMgr &SrcMgr, MCContext &Ctx, MCStreamer &Str, |
326 | MCAsmInfo &MAI, MCSubtargetInfo &STI, |
327 | MCInstrInfo &MCII, MCTargetOptions const &MCOptions) { |
328 | std::unique_ptr<MCAsmParser> Parser( |
329 | createMCAsmParser(SrcMgr, Ctx, Str, MAI)); |
330 | std::unique_ptr<MCTargetAsmParser> TAP( |
331 | TheTarget->createMCAsmParser(STI, Parser&: *Parser, MII: MCII, Options: MCOptions)); |
332 | |
333 | if (!TAP) { |
334 | WithColor::error(OS&: errs(), Prefix: ProgName) |
335 | << "this target does not support assembly parsing.\n" ; |
336 | return 1; |
337 | } |
338 | |
339 | int SymbolResult = fillCommandLineSymbols(Parser&: *Parser); |
340 | if(SymbolResult) |
341 | return SymbolResult; |
342 | Parser->setShowParsedOperands(ShowInstOperands); |
343 | Parser->setTargetParser(*TAP); |
344 | Parser->getLexer().setLexMasmIntegers(LexMasmIntegers); |
345 | Parser->getLexer().setLexMasmHexFloats(LexMasmHexFloats); |
346 | Parser->getLexer().setLexMotorolaIntegers(LexMotorolaIntegers); |
347 | |
348 | int Res = Parser->Run(NoInitialTextSection); |
349 | |
350 | return Res; |
351 | } |
352 | |
353 | int main(int argc, char **argv) { |
354 | InitLLVM X(argc, argv); |
355 | |
356 | // Initialize targets and assembly printers/parsers. |
357 | llvm::InitializeAllTargetInfos(); |
358 | llvm::InitializeAllTargetMCs(); |
359 | llvm::InitializeAllAsmParsers(); |
360 | llvm::InitializeAllDisassemblers(); |
361 | |
362 | // Register the target printer for --version. |
363 | cl::AddExtraVersionPrinter(func: TargetRegistry::printRegisteredTargetsForVersion); |
364 | |
365 | cl::HideUnrelatedOptions(Categories: {&MCCategory, &getColorCategory()}); |
366 | cl::ParseCommandLineOptions(argc, argv, Overview: "llvm machine code playground\n" ); |
367 | MCTargetOptions MCOptions = mc::InitMCTargetOptionsFromFlags(); |
368 | MCOptions.CompressDebugSections = CompressDebugSections.getValue(); |
369 | MCOptions.ShowMCInst = ShowInst; |
370 | MCOptions.AsmVerbose = true; |
371 | MCOptions.MCUseDwarfDirectory = MCTargetOptions::EnableDwarfDirectory; |
372 | MCOptions.InstPrinterOptions = InstPrinterOptions; |
373 | |
374 | setDwarfDebugFlags(argc, argv); |
375 | setDwarfDebugProducer(); |
376 | |
377 | const char *ProgName = argv[0]; |
378 | const Target *TheTarget = GetTarget(ProgName); |
379 | if (!TheTarget) |
380 | return 1; |
381 | // Now that GetTarget() has (potentially) replaced TripleName, it's safe to |
382 | // construct the Triple object. |
383 | Triple TheTriple(TripleName); |
384 | |
385 | ErrorOr<std::unique_ptr<MemoryBuffer>> BufferPtr = |
386 | MemoryBuffer::getFileOrSTDIN(Filename: InputFilename, /*IsText=*/true); |
387 | if (std::error_code EC = BufferPtr.getError()) { |
388 | WithColor::error(OS&: errs(), Prefix: ProgName) |
389 | << InputFilename << ": " << EC.message() << '\n'; |
390 | return 1; |
391 | } |
392 | MemoryBuffer *Buffer = BufferPtr->get(); |
393 | |
394 | SourceMgr SrcMgr; |
395 | |
396 | // Tell SrcMgr about this buffer, which is what the parser will pick up. |
397 | SrcMgr.AddNewSourceBuffer(F: std::move(*BufferPtr), IncludeLoc: SMLoc()); |
398 | |
399 | // Record the location of the include directories so that the lexer can find |
400 | // it later. |
401 | SrcMgr.setIncludeDirs(IncludeDirs); |
402 | |
403 | std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT: TripleName)); |
404 | assert(MRI && "Unable to create target register info!" ); |
405 | |
406 | std::unique_ptr<MCAsmInfo> MAI( |
407 | TheTarget->createMCAsmInfo(MRI: *MRI, TheTriple: TripleName, Options: MCOptions)); |
408 | assert(MAI && "Unable to create target asm info!" ); |
409 | |
410 | if (CompressDebugSections != DebugCompressionType::None) { |
411 | if (const char *Reason = compression::getReasonIfUnsupported( |
412 | F: compression::formatFor(Type: CompressDebugSections))) { |
413 | WithColor::error(OS&: errs(), Prefix: ProgName) |
414 | << "--compress-debug-sections: " << Reason; |
415 | return 1; |
416 | } |
417 | } |
418 | MAI->setPreserveAsmComments(PreserveComments); |
419 | MAI->setCommentColumn(CommentColumn); |
420 | |
421 | // Package up features to be passed to target/subtarget |
422 | std::string FeaturesStr; |
423 | if (MAttrs.size()) { |
424 | SubtargetFeatures Features; |
425 | for (unsigned i = 0; i != MAttrs.size(); ++i) |
426 | Features.AddFeature(String: MAttrs[i]); |
427 | FeaturesStr = Features.getString(); |
428 | } |
429 | |
430 | std::unique_ptr<MCSubtargetInfo> STI( |
431 | TheTarget->createMCSubtargetInfo(TheTriple: TripleName, CPU: MCPU, Features: FeaturesStr)); |
432 | assert(STI && "Unable to create subtarget info!" ); |
433 | |
434 | // FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and |
435 | // MCObjectFileInfo needs a MCContext reference in order to initialize itself. |
436 | MCContext Ctx(TheTriple, MAI.get(), MRI.get(), STI.get(), &SrcMgr, |
437 | &MCOptions); |
438 | std::unique_ptr<MCObjectFileInfo> MOFI( |
439 | TheTarget->createMCObjectFileInfo(Ctx, PIC, LargeCodeModel)); |
440 | Ctx.setObjectFileInfo(MOFI.get()); |
441 | |
442 | Ctx.setGenDwarfForAssembly(GenDwarfForAssembly); |
443 | // Default to 4 for dwarf version. |
444 | unsigned DwarfVersion = MCOptions.DwarfVersion ? MCOptions.DwarfVersion : 4; |
445 | if (DwarfVersion < 2 || DwarfVersion > 5) { |
446 | errs() << ProgName << ": Dwarf version " << DwarfVersion |
447 | << " is not supported." << '\n'; |
448 | return 1; |
449 | } |
450 | Ctx.setDwarfVersion(DwarfVersion); |
451 | if (MCOptions.Dwarf64) { |
452 | // The 64-bit DWARF format was introduced in DWARFv3. |
453 | if (DwarfVersion < 3) { |
454 | errs() << ProgName |
455 | << ": the 64-bit DWARF format is not supported for DWARF versions " |
456 | "prior to 3\n" ; |
457 | return 1; |
458 | } |
459 | // 32-bit targets don't support DWARF64, which requires 64-bit relocations. |
460 | if (MAI->getCodePointerSize() < 8) { |
461 | errs() << ProgName |
462 | << ": the 64-bit DWARF format is only supported for 64-bit " |
463 | "targets\n" ; |
464 | return 1; |
465 | } |
466 | // If needsDwarfSectionOffsetDirective is true, we would eventually call |
467 | // MCStreamer::emitSymbolValue() with IsSectionRelative = true, but that |
468 | // is supported only for 4-byte long references. |
469 | if (MAI->needsDwarfSectionOffsetDirective()) { |
470 | errs() << ProgName << ": the 64-bit DWARF format is not supported for " |
471 | << TheTriple.normalize() << "\n" ; |
472 | return 1; |
473 | } |
474 | Ctx.setDwarfFormat(dwarf::DWARF64); |
475 | } |
476 | if (!DwarfDebugFlags.empty()) |
477 | Ctx.setDwarfDebugFlags(StringRef(DwarfDebugFlags)); |
478 | if (!DwarfDebugProducer.empty()) |
479 | Ctx.setDwarfDebugProducer(StringRef(DwarfDebugProducer)); |
480 | if (!DebugCompilationDir.empty()) |
481 | Ctx.setCompilationDir(DebugCompilationDir); |
482 | else { |
483 | // If no compilation dir is set, try to use the current directory. |
484 | SmallString<128> CWD; |
485 | if (!sys::fs::current_path(result&: CWD)) |
486 | Ctx.setCompilationDir(CWD); |
487 | } |
488 | for (const auto &Arg : DebugPrefixMap) { |
489 | const auto &KV = StringRef(Arg).split(Separator: '='); |
490 | Ctx.addDebugPrefixMapEntry(From: std::string(KV.first), To: std::string(KV.second)); |
491 | } |
492 | if (!MainFileName.empty()) |
493 | Ctx.setMainFileName(MainFileName); |
494 | if (GenDwarfForAssembly) |
495 | Ctx.setGenDwarfRootFile(FileName: InputFilename, Buffer: Buffer->getBuffer()); |
496 | |
497 | sys::fs::OpenFlags Flags = (FileType == OFT_AssemblyFile) |
498 | ? sys::fs::OF_TextWithCRLF |
499 | : sys::fs::OF_None; |
500 | std::unique_ptr<ToolOutputFile> Out = GetOutputStream(Path: OutputFilename, Flags); |
501 | if (!Out) |
502 | return 1; |
503 | |
504 | std::unique_ptr<ToolOutputFile> DwoOut; |
505 | if (!SplitDwarfFile.empty()) { |
506 | if (FileType != OFT_ObjectFile) { |
507 | WithColor::error() << "dwo output only supported with object files\n" ; |
508 | return 1; |
509 | } |
510 | DwoOut = GetOutputStream(Path: SplitDwarfFile, Flags: sys::fs::OF_None); |
511 | if (!DwoOut) |
512 | return 1; |
513 | } |
514 | |
515 | std::unique_ptr<buffer_ostream> BOS; |
516 | raw_pwrite_stream *OS = &Out->os(); |
517 | std::unique_ptr<MCStreamer> Str; |
518 | |
519 | std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo()); |
520 | assert(MCII && "Unable to create instruction info!" ); |
521 | |
522 | std::unique_ptr<MCInstPrinter> IP; |
523 | if (FileType == OFT_AssemblyFile) { |
524 | IP.reset(p: TheTarget->createMCInstPrinter( |
525 | T: Triple(TripleName), SyntaxVariant: OutputAsmVariant, MAI: *MAI, MII: *MCII, MRI: *MRI)); |
526 | |
527 | if (!IP) { |
528 | WithColor::error() |
529 | << "unable to create instruction printer for target triple '" |
530 | << TheTriple.normalize() << "' with assembly variant " |
531 | << OutputAsmVariant << ".\n" ; |
532 | return 1; |
533 | } |
534 | |
535 | for (StringRef Opt : InstPrinterOptions) |
536 | if (!IP->applyTargetSpecificCLOption(Opt)) { |
537 | WithColor::error() << "invalid InstPrinter option '" << Opt << "'\n" ; |
538 | return 1; |
539 | } |
540 | |
541 | // Set the display preference for hex vs. decimal immediates. |
542 | IP->setPrintImmHex(PrintImmHex); |
543 | |
544 | switch (Action) { |
545 | case AC_MDisassemble: |
546 | IP->setUseMarkup(true); |
547 | break; |
548 | case AC_CDisassemble: |
549 | IP->setUseColor(true); |
550 | break; |
551 | default: |
552 | break; |
553 | } |
554 | |
555 | // Set up the AsmStreamer. |
556 | std::unique_ptr<MCCodeEmitter> CE; |
557 | if (ShowEncoding) |
558 | CE.reset(p: TheTarget->createMCCodeEmitter(II: *MCII, Ctx)); |
559 | |
560 | std::unique_ptr<MCAsmBackend> MAB( |
561 | TheTarget->createMCAsmBackend(STI: *STI, MRI: *MRI, Options: MCOptions)); |
562 | auto FOut = std::make_unique<formatted_raw_ostream>(args&: *OS); |
563 | Str.reset(p: TheTarget->createAsmStreamer(Ctx, OS: std::move(FOut), IP: std::move(IP), |
564 | CE: std::move(CE), TAB: std::move(MAB))); |
565 | |
566 | } else if (FileType == OFT_Null) { |
567 | Str.reset(p: TheTarget->createNullStreamer(Ctx)); |
568 | } else { |
569 | assert(FileType == OFT_ObjectFile && "Invalid file type!" ); |
570 | |
571 | if (!Out->os().supportsSeeking()) { |
572 | BOS = std::make_unique<buffer_ostream>(args&: Out->os()); |
573 | OS = BOS.get(); |
574 | } |
575 | |
576 | MCCodeEmitter *CE = TheTarget->createMCCodeEmitter(II: *MCII, Ctx); |
577 | MCAsmBackend *MAB = TheTarget->createMCAsmBackend(STI: *STI, MRI: *MRI, Options: MCOptions); |
578 | Str.reset(p: TheTarget->createMCObjectStreamer( |
579 | T: TheTriple, Ctx, TAB: std::unique_ptr<MCAsmBackend>(MAB), |
580 | OW: DwoOut ? MAB->createDwoObjectWriter(OS&: *OS, DwoOS&: DwoOut->os()) |
581 | : MAB->createObjectWriter(OS&: *OS), |
582 | Emitter: std::unique_ptr<MCCodeEmitter>(CE), STI: *STI)); |
583 | if (NoExecStack) |
584 | Str->switchSection(Section: Ctx.getAsmInfo()->getNonexecutableStackSection(Ctx)); |
585 | Str->emitVersionForTarget(Target: TheTriple, SDKVersion: VersionTuple(), DarwinTargetVariantTriple: nullptr, |
586 | DarwinTargetVariantSDKVersion: VersionTuple()); |
587 | } |
588 | |
589 | int Res = 1; |
590 | bool disassemble = false; |
591 | switch (Action) { |
592 | case AC_AsLex: |
593 | Res = AsLexInput(SrcMgr, MAI&: *MAI, OS&: Out->os()); |
594 | break; |
595 | case AC_Assemble: |
596 | Res = AssembleInput(ProgName, TheTarget, SrcMgr, Ctx, Str&: *Str, MAI&: *MAI, STI&: *STI, |
597 | MCII&: *MCII, MCOptions); |
598 | break; |
599 | case AC_MDisassemble: |
600 | case AC_CDisassemble: |
601 | case AC_Disassemble: |
602 | disassemble = true; |
603 | break; |
604 | } |
605 | if (disassemble) |
606 | Res = Disassembler::disassemble(T: *TheTarget, Triple: TripleName, STI&: *STI, Streamer&: *Str, Buffer&: *Buffer, |
607 | SM&: SrcMgr, Ctx, MCOptions, HexBytes); |
608 | |
609 | // Keep output if no errors. |
610 | if (Res == 0) { |
611 | Out->keep(); |
612 | if (DwoOut) |
613 | DwoOut->keep(); |
614 | } |
615 | return Res; |
616 | } |
617 | |