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