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