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