1//===-- llvm-mc.cpp - Machine Code Hacking Driver -------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This utility is a simple driver that allows command line hacking on machine
11// code.
12//
13//===----------------------------------------------------------------------===//
14
15#include "llvm/MC/MCParser/AsmLexer.h"
16#include "llvm/MC/MCParser/MCAsmLexer.h"
17#include "llvm/MC/MCAsmBackend.h"
18#include "llvm/MC/MCContext.h"
19#include "llvm/MC/MCCodeEmitter.h"
20#include "llvm/MC/MCInstPrinter.h"
21#include "llvm/MC/MCInstrInfo.h"
22#include "llvm/MC/MCObjectFileInfo.h"
23#include "llvm/MC/MCRegisterInfo.h"
24#include "llvm/MC/MCSectionMachO.h"
25#include "llvm/MC/MCStreamer.h"
26#include "llvm/MC/MCSubtargetInfo.h"
27#include "llvm/MC/MCTargetAsmParser.h"
28#include "llvm/MC/SubtargetFeature.h"
29#include "llvm/ADT/OwningPtr.h"
30#include "llvm/Support/CommandLine.h"
31#include "llvm/Support/FileUtilities.h"
32#include "llvm/Support/FormattedStream.h"
33#include "llvm/Support/ManagedStatic.h"
34#include "llvm/Support/MemoryBuffer.h"
35#include "llvm/Support/PrettyStackTrace.h"
36#include "llvm/Support/SourceMgr.h"
37#include "llvm/Support/ToolOutputFile.h"
38#include "llvm/Support/Host.h"
39#include "llvm/Support/Signals.h"
40#include "llvm/Support/TargetRegistry.h"
41#include "llvm/Support/TargetSelect.h"
42#include "llvm/Support/system_error.h"
43#include "Disassembler.h"
44using namespace llvm;
45
46static cl::opt<std::string>
47InputFilename(cl::Positional, cl::desc("<input file>"), cl::init("-"));
48
49static cl::opt<std::string>
50OutputFilename("o", cl::desc("Output filename"),
51               cl::value_desc("filename"));
52
53static cl::opt<bool>
54ShowEncoding("show-encoding", cl::desc("Show instruction encodings"));
55
56static cl::opt<bool>
57ShowInst("show-inst", cl::desc("Show internal instruction representation"));
58
59static cl::opt<bool>
60ShowInstOperands("show-inst-operands",
61                 cl::desc("Show instructions operands as parsed"));
62
63static cl::opt<unsigned>
64OutputAsmVariant("output-asm-variant",
65                 cl::desc("Syntax variant to use for output printing"));
66
67static cl::opt<bool>
68RelaxAll("mc-relax-all", cl::desc("Relax all fixups"));
69
70static cl::opt<bool>
71NoExecStack("mc-no-exec-stack", cl::desc("File doesn't need an exec stack"));
72
73static cl::opt<bool>
74EnableLogging("enable-api-logging", cl::desc("Enable MC API logging"));
75
76enum OutputFileType {
77  OFT_Null,
78  OFT_AssemblyFile,
79  OFT_ObjectFile
80};
81static cl::opt<OutputFileType>
82FileType("filetype", cl::init(OFT_AssemblyFile),
83  cl::desc("Choose an output file type:"),
84  cl::values(
85       clEnumValN(OFT_AssemblyFile, "asm",
86                  "Emit an assembly ('.s') file"),
87       clEnumValN(OFT_Null, "null",
88                  "Don't emit anything (for timing purposes)"),
89       clEnumValN(OFT_ObjectFile, "obj",
90                  "Emit a native object ('.o') file"),
91       clEnumValEnd));
92
93static cl::list<std::string>
94IncludeDirs("I", cl::desc("Directory of include files"),
95            cl::value_desc("directory"), cl::Prefix);
96
97static cl::opt<std::string>
98ArchName("arch", cl::desc("Target arch to assemble for, "
99                          "see -version for available targets"));
100
101static cl::opt<std::string>
102TripleName("triple", cl::desc("Target triple to assemble for, "
103                              "see -version for available targets"));
104
105static cl::opt<std::string>
106MCPU("mcpu",
107     cl::desc("Target a specific cpu type (-mcpu=help for details)"),
108     cl::value_desc("cpu-name"),
109     cl::init(""));
110
111static cl::list<std::string>
112MAttrs("mattr",
113  cl::CommaSeparated,
114  cl::desc("Target specific attributes (-mattr=help for details)"),
115  cl::value_desc("a1,+a2,-a3,..."));
116
117static cl::opt<Reloc::Model>
118RelocModel("relocation-model",
119             cl::desc("Choose relocation model"),
120             cl::init(Reloc::Default),
121             cl::values(
122            clEnumValN(Reloc::Default, "default",
123                       "Target default relocation model"),
124            clEnumValN(Reloc::Static, "static",
125                       "Non-relocatable code"),
126            clEnumValN(Reloc::PIC_, "pic",
127                       "Fully relocatable, position independent code"),
128            clEnumValN(Reloc::DynamicNoPIC, "dynamic-no-pic",
129                       "Relocatable external references, non-relocatable code"),
130            clEnumValEnd));
131
132static cl::opt<llvm::CodeModel::Model>
133CMModel("code-model",
134        cl::desc("Choose code model"),
135        cl::init(CodeModel::Default),
136        cl::values(clEnumValN(CodeModel::Default, "default",
137                              "Target default code model"),
138                   clEnumValN(CodeModel::Small, "small",
139                              "Small code model"),
140                   clEnumValN(CodeModel::Kernel, "kernel",
141                              "Kernel code model"),
142                   clEnumValN(CodeModel::Medium, "medium",
143                              "Medium code model"),
144                   clEnumValN(CodeModel::Large, "large",
145                              "Large code model"),
146                   clEnumValEnd));
147
148static cl::opt<bool>
149NoInitialTextSection("n", cl::desc("Don't assume assembly file starts "
150                                   "in the text section"));
151
152static cl::opt<bool>
153SaveTempLabels("L", cl::desc("Don't discard temporary labels"));
154
155enum ActionType {
156  AC_AsLex,
157  AC_Assemble,
158  AC_Disassemble,
159  AC_EDisassemble
160};
161
162static cl::opt<ActionType>
163Action(cl::desc("Action to perform:"),
164       cl::init(AC_Assemble),
165       cl::values(clEnumValN(AC_AsLex, "as-lex",
166                             "Lex tokens from a .s file"),
167                  clEnumValN(AC_Assemble, "assemble",
168                             "Assemble a .s file (default)"),
169                  clEnumValN(AC_Disassemble, "disassemble",
170                             "Disassemble strings of hex bytes"),
171                  clEnumValN(AC_EDisassemble, "edis",
172                             "Enhanced disassembly of strings of hex bytes"),
173                  clEnumValEnd));
174
175static const Target *GetTarget(const char *ProgName) {
176  // Figure out the target triple.
177  if (TripleName.empty())
178    TripleName = sys::getHostTriple();
179  Triple TheTriple(Triple::normalize(TripleName));
180
181  const Target *TheTarget = 0;
182  if (!ArchName.empty()) {
183    for (TargetRegistry::iterator it = TargetRegistry::begin(),
184           ie = TargetRegistry::end(); it != ie; ++it) {
185      if (ArchName == it->getName()) {
186        TheTarget = &*it;
187        break;
188      }
189    }
190
191    if (!TheTarget) {
192      errs() << ProgName << ": error: invalid target '" << ArchName << "'.\n";
193      return 0;
194    }
195
196    // Adjust the triple to match (if known), otherwise stick with the
197    // module/host triple.
198    Triple::ArchType Type = Triple::getArchTypeForLLVMName(ArchName);
199    if (Type != Triple::UnknownArch)
200      TheTriple.setArch(Type);
201  } else {
202    // Get the target specific parser.
203    std::string Error;
204    TheTarget = TargetRegistry::lookupTarget(TheTriple.getTriple(), Error);
205    if (TheTarget == 0) {
206      errs() << ProgName << ": error: unable to get target for '"
207             << TheTriple.getTriple()
208             << "', see --version and --triple.\n";
209      return 0;
210    }
211  }
212
213  TripleName = TheTriple.getTriple();
214  return TheTarget;
215}
216
217static tool_output_file *GetOutputStream() {
218  if (OutputFilename == "")
219    OutputFilename = "-";
220
221  std::string Err;
222  tool_output_file *Out = new tool_output_file(OutputFilename.c_str(), Err,
223                                               raw_fd_ostream::F_Binary);
224  if (!Err.empty()) {
225    errs() << Err << '\n';
226    delete Out;
227    return 0;
228  }
229
230  return Out;
231}
232
233static int AsLexInput(const char *ProgName) {
234  OwningPtr<MemoryBuffer> BufferPtr;
235  if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFilename, BufferPtr)) {
236    errs() << ProgName << ": " << ec.message() << '\n';
237    return 1;
238  }
239  MemoryBuffer *Buffer = BufferPtr.take();
240
241  SourceMgr SrcMgr;
242
243  // Tell SrcMgr about this buffer, which is what TGParser will pick up.
244  SrcMgr.AddNewSourceBuffer(Buffer, SMLoc());
245
246  // Record the location of the include directories so that the lexer can find
247  // it later.
248  SrcMgr.setIncludeDirs(IncludeDirs);
249
250  const Target *TheTarget = GetTarget(ProgName);
251  if (!TheTarget)
252    return 1;
253
254  llvm::OwningPtr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(TripleName));
255  assert(MAI && "Unable to create target asm info!");
256
257  AsmLexer Lexer(*MAI);
258  Lexer.setBuffer(SrcMgr.getMemoryBuffer(0));
259
260  OwningPtr<tool_output_file> Out(GetOutputStream());
261  if (!Out)
262    return 1;
263
264  bool Error = false;
265  while (Lexer.Lex().isNot(AsmToken::Eof)) {
266    AsmToken Tok = Lexer.getTok();
267
268    switch (Tok.getKind()) {
269    default:
270      SrcMgr.PrintMessage(Lexer.getLoc(), "unknown token", "warning");
271      Error = true;
272      break;
273    case AsmToken::Error:
274      Error = true; // error already printed.
275      break;
276    case AsmToken::Identifier:
277      Out->os() << "identifier: " << Lexer.getTok().getString();
278      break;
279    case AsmToken::Integer:
280      Out->os() << "int: " << Lexer.getTok().getString();
281      break;
282    case AsmToken::Real:
283      Out->os() << "real: " << Lexer.getTok().getString();
284      break;
285    case AsmToken::Register:
286      Out->os() << "register: " << Lexer.getTok().getRegVal();
287      break;
288    case AsmToken::String:
289      Out->os() << "string: " << Lexer.getTok().getString();
290      break;
291
292    case AsmToken::Amp:            Out->os() << "Amp"; break;
293    case AsmToken::AmpAmp:         Out->os() << "AmpAmp"; break;
294    case AsmToken::At:             Out->os() << "At"; break;
295    case AsmToken::Caret:          Out->os() << "Caret"; break;
296    case AsmToken::Colon:          Out->os() << "Colon"; break;
297    case AsmToken::Comma:          Out->os() << "Comma"; break;
298    case AsmToken::Dollar:         Out->os() << "Dollar"; break;
299    case AsmToken::Dot:            Out->os() << "Dot"; break;
300    case AsmToken::EndOfStatement: Out->os() << "EndOfStatement"; break;
301    case AsmToken::Eof:            Out->os() << "Eof"; break;
302    case AsmToken::Equal:          Out->os() << "Equal"; break;
303    case AsmToken::EqualEqual:     Out->os() << "EqualEqual"; break;
304    case AsmToken::Exclaim:        Out->os() << "Exclaim"; break;
305    case AsmToken::ExclaimEqual:   Out->os() << "ExclaimEqual"; break;
306    case AsmToken::Greater:        Out->os() << "Greater"; break;
307    case AsmToken::GreaterEqual:   Out->os() << "GreaterEqual"; break;
308    case AsmToken::GreaterGreater: Out->os() << "GreaterGreater"; break;
309    case AsmToken::Hash:           Out->os() << "Hash"; break;
310    case AsmToken::LBrac:          Out->os() << "LBrac"; break;
311    case AsmToken::LCurly:         Out->os() << "LCurly"; break;
312    case AsmToken::LParen:         Out->os() << "LParen"; break;
313    case AsmToken::Less:           Out->os() << "Less"; break;
314    case AsmToken::LessEqual:      Out->os() << "LessEqual"; break;
315    case AsmToken::LessGreater:    Out->os() << "LessGreater"; break;
316    case AsmToken::LessLess:       Out->os() << "LessLess"; break;
317    case AsmToken::Minus:          Out->os() << "Minus"; break;
318    case AsmToken::Percent:        Out->os() << "Percent"; break;
319    case AsmToken::Pipe:           Out->os() << "Pipe"; break;
320    case AsmToken::PipePipe:       Out->os() << "PipePipe"; break;
321    case AsmToken::Plus:           Out->os() << "Plus"; break;
322    case AsmToken::RBrac:          Out->os() << "RBrac"; break;
323    case AsmToken::RCurly:         Out->os() << "RCurly"; break;
324    case AsmToken::RParen:         Out->os() << "RParen"; break;
325    case AsmToken::Slash:          Out->os() << "Slash"; break;
326    case AsmToken::Star:           Out->os() << "Star"; break;
327    case AsmToken::Tilde:          Out->os() << "Tilde"; break;
328    }
329
330    // Print the token string.
331    Out->os() << " (\"";
332    Out->os().write_escaped(Tok.getString());
333    Out->os() << "\")\n";
334  }
335
336  // Keep output if no errors.
337  if (Error == 0) Out->keep();
338
339  return Error;
340}
341
342static int AssembleInput(const char *ProgName) {
343  const Target *TheTarget = GetTarget(ProgName);
344  if (!TheTarget)
345    return 1;
346
347  OwningPtr<MemoryBuffer> BufferPtr;
348  if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFilename, BufferPtr)) {
349    errs() << ProgName << ": " << ec.message() << '\n';
350    return 1;
351  }
352  MemoryBuffer *Buffer = BufferPtr.take();
353
354  SourceMgr SrcMgr;
355
356  // Tell SrcMgr about this buffer, which is what the parser will pick up.
357  SrcMgr.AddNewSourceBuffer(Buffer, SMLoc());
358
359  // Record the location of the include directories so that the lexer can find
360  // it later.
361  SrcMgr.setIncludeDirs(IncludeDirs);
362
363
364  llvm::OwningPtr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(TripleName));
365  assert(MAI && "Unable to create target asm info!");
366
367  llvm::OwningPtr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName));
368  assert(MRI && "Unable to create target register info!");
369
370  // FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and
371  // MCObjectFileInfo needs a MCContext reference in order to initialize itself.
372  OwningPtr<MCObjectFileInfo> MOFI(new MCObjectFileInfo());
373  MCContext Ctx(*MAI, *MRI, MOFI.get());
374  MOFI->InitMCObjectFileInfo(TripleName, RelocModel, CMModel, Ctx);
375
376  if (SaveTempLabels)
377    Ctx.setAllowTemporaryLabels(false);
378
379  // Package up features to be passed to target/subtarget
380  std::string FeaturesStr;
381  if (MAttrs.size()) {
382    SubtargetFeatures Features;
383    for (unsigned i = 0; i != MAttrs.size(); ++i)
384      Features.AddFeature(MAttrs[i]);
385    FeaturesStr = Features.getString();
386  }
387
388  OwningPtr<tool_output_file> Out(GetOutputStream());
389  if (!Out)
390    return 1;
391
392  formatted_raw_ostream FOS(Out->os());
393  OwningPtr<MCStreamer> Str;
394
395  OwningPtr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo());
396  OwningPtr<MCSubtargetInfo>
397    STI(TheTarget->createMCSubtargetInfo(TripleName, MCPU, FeaturesStr));
398
399  // FIXME: There is a bit of code duplication with addPassesToEmitFile.
400  if (FileType == OFT_AssemblyFile) {
401    MCInstPrinter *IP =
402      TheTarget->createMCInstPrinter(OutputAsmVariant, *MAI, *STI);
403    MCCodeEmitter *CE = 0;
404    MCAsmBackend *MAB = 0;
405    if (ShowEncoding) {
406      CE = TheTarget->createMCCodeEmitter(*MCII, *STI, Ctx);
407      MAB = TheTarget->createMCAsmBackend(TripleName);
408    }
409    Str.reset(TheTarget->createAsmStreamer(Ctx, FOS, /*asmverbose*/true,
410                                           /*useLoc*/ true,
411                                           /*useCFI*/ true, IP, CE, MAB,
412                                           ShowInst));
413  } else if (FileType == OFT_Null) {
414    Str.reset(createNullStreamer(Ctx));
415  } else {
416    assert(FileType == OFT_ObjectFile && "Invalid file type!");
417    MCCodeEmitter *CE = TheTarget->createMCCodeEmitter(*MCII, *STI, Ctx);
418    MCAsmBackend *MAB = TheTarget->createMCAsmBackend(TripleName);
419    Str.reset(TheTarget->createMCObjectStreamer(TripleName, Ctx, *MAB,
420                                                FOS, CE, RelaxAll,
421                                                NoExecStack));
422  }
423
424  if (EnableLogging) {
425    Str.reset(createLoggingStreamer(Str.take(), errs()));
426  }
427
428  OwningPtr<MCAsmParser> Parser(createMCAsmParser(SrcMgr, Ctx,
429                                                  *Str.get(), *MAI));
430  OwningPtr<MCTargetAsmParser> TAP(TheTarget->createMCAsmParser(*STI, *Parser));
431  if (!TAP) {
432    errs() << ProgName
433           << ": error: this target does not support assembly parsing.\n";
434    return 1;
435  }
436
437  Parser->setShowParsedOperands(ShowInstOperands);
438  Parser->setTargetParser(*TAP.get());
439
440  int Res = Parser->Run(NoInitialTextSection);
441
442  // Keep output if no errors.
443  if (Res == 0) Out->keep();
444
445  return Res;
446}
447
448static int DisassembleInput(const char *ProgName, bool Enhanced) {
449  const Target *TheTarget = GetTarget(ProgName);
450  if (!TheTarget)
451    return 0;
452
453  OwningPtr<MemoryBuffer> Buffer;
454  if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFilename, Buffer)) {
455    errs() << ProgName << ": " << ec.message() << '\n';
456    return 1;
457  }
458
459  OwningPtr<tool_output_file> Out(GetOutputStream());
460  if (!Out)
461    return 1;
462
463  int Res;
464  if (Enhanced) {
465    Res =
466      Disassembler::disassembleEnhanced(TripleName, *Buffer.take(), Out->os());
467  } else {
468    // Package up features to be passed to target/subtarget
469    std::string FeaturesStr;
470    if (MAttrs.size()) {
471      SubtargetFeatures Features;
472      for (unsigned i = 0; i != MAttrs.size(); ++i)
473        Features.AddFeature(MAttrs[i]);
474      FeaturesStr = Features.getString();
475    }
476
477    Res = Disassembler::disassemble(*TheTarget, TripleName, MCPU, FeaturesStr,
478                                    *Buffer.take(), Out->os());
479  }
480
481  // Keep output if no errors.
482  if (Res == 0) Out->keep();
483
484  return Res;
485}
486
487
488int main(int argc, char **argv) {
489  // Print a stack trace if we signal out.
490  sys::PrintStackTraceOnErrorSignal();
491  PrettyStackTraceProgram X(argc, argv);
492  llvm_shutdown_obj Y;  // Call llvm_shutdown() on exit.
493
494  // Initialize targets and assembly printers/parsers.
495  llvm::InitializeAllTargetInfos();
496  llvm::InitializeAllTargetMCs();
497  llvm::InitializeAllAsmParsers();
498  llvm::InitializeAllDisassemblers();
499
500  cl::ParseCommandLineOptions(argc, argv, "llvm machine code playground\n");
501  TripleName = Triple::normalize(TripleName);
502
503  switch (Action) {
504  default:
505  case AC_AsLex:
506    return AsLexInput(argv[0]);
507  case AC_Assemble:
508    return AssembleInput(argv[0]);
509  case AC_Disassemble:
510    return DisassembleInput(argv[0], false);
511  case AC_EDisassemble:
512    return DisassembleInput(argv[0], true);
513  }
514
515  return 0;
516}
517
518