llvm-mc.cpp revision d4c454317a38d65957edebe62bfc69fc8d9885e8
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/MCContext.h"
18#include "llvm/MC/MCCodeEmitter.h"
19#include "llvm/MC/MCInstPrinter.h"
20#include "llvm/MC/MCSectionMachO.h"
21#include "llvm/MC/MCStreamer.h"
22#include "llvm/Target/TargetAsmBackend.h"
23#include "llvm/Target/TargetAsmParser.h"
24#include "llvm/Target/TargetData.h"
25#include "llvm/Target/TargetRegistry.h"
26#include "llvm/Target/TargetMachine.h"  // FIXME.
27#include "llvm/Target/TargetSelect.h"
28#include "llvm/ADT/OwningPtr.h"
29#include "llvm/Support/CommandLine.h"
30#include "llvm/Support/FileUtilities.h"
31#include "llvm/Support/FormattedStream.h"
32#include "llvm/Support/ManagedStatic.h"
33#include "llvm/Support/MemoryBuffer.h"
34#include "llvm/Support/PrettyStackTrace.h"
35#include "llvm/Support/SourceMgr.h"
36#include "llvm/Support/raw_ostream.h"
37#include "llvm/System/Host.h"
38#include "llvm/System/Signals.h"
39#include "Disassembler.h"
40using namespace llvm;
41
42static cl::opt<std::string>
43InputFilename(cl::Positional, cl::desc("<input file>"), cl::init("-"));
44
45static cl::opt<std::string>
46OutputFilename("o", cl::desc("Output filename"),
47               cl::value_desc("filename"));
48
49static cl::opt<bool>
50ShowEncoding("show-encoding", cl::desc("Show instruction encodings"));
51
52static cl::opt<bool>
53ShowInst("show-inst", cl::desc("Show internal instruction representation"));
54
55static cl::opt<bool>
56ShowInstOperands("show-inst-operands",
57                 cl::desc("Show instructions operands as parsed"));
58
59static cl::opt<unsigned>
60OutputAsmVariant("output-asm-variant",
61                 cl::desc("Syntax variant to use for output printing"));
62
63static cl::opt<bool>
64RelaxAll("mc-relax-all", cl::desc("Relax all fixups"));
65
66static cl::opt<bool>
67EnableLogging("enable-api-logging", cl::desc("Enable MC API logging"));
68
69enum OutputFileType {
70  OFT_Null,
71  OFT_AssemblyFile,
72  OFT_ObjectFile
73};
74static cl::opt<OutputFileType>
75FileType("filetype", cl::init(OFT_AssemblyFile),
76  cl::desc("Choose an output file type:"),
77  cl::values(
78       clEnumValN(OFT_AssemblyFile, "asm",
79                  "Emit an assembly ('.s') file"),
80       clEnumValN(OFT_Null, "null",
81                  "Don't emit anything (for timing purposes)"),
82       clEnumValN(OFT_ObjectFile, "obj",
83                  "Emit a native object ('.o') file"),
84       clEnumValEnd));
85
86static cl::list<std::string>
87IncludeDirs("I", cl::desc("Directory of include files"),
88            cl::value_desc("directory"), cl::Prefix);
89
90static cl::opt<std::string>
91ArchName("arch", cl::desc("Target arch to assemble for, "
92                            "see -version for available targets"));
93
94static cl::opt<std::string>
95TripleName("triple", cl::desc("Target triple to assemble for, "
96                              "see -version for available targets"));
97
98static cl::opt<bool>
99NoInitialTextSection("n", cl::desc(
100                   "Don't assume assembly file starts in the text section"));
101
102enum ActionType {
103  AC_AsLex,
104  AC_Assemble,
105  AC_Disassemble,
106  AC_EDisassemble
107};
108
109static cl::opt<ActionType>
110Action(cl::desc("Action to perform:"),
111       cl::init(AC_Assemble),
112       cl::values(clEnumValN(AC_AsLex, "as-lex",
113                             "Lex tokens from a .s file"),
114                  clEnumValN(AC_Assemble, "assemble",
115                             "Assemble a .s file (default)"),
116                  clEnumValN(AC_Disassemble, "disassemble",
117                             "Disassemble strings of hex bytes"),
118                  clEnumValN(AC_EDisassemble, "edis",
119                             "Enhanced disassembly of strings of hex bytes"),
120                  clEnumValEnd));
121
122static const Target *GetTarget(const char *ProgName) {
123  // Figure out the target triple.
124  if (TripleName.empty())
125    TripleName = sys::getHostTriple();
126  if (!ArchName.empty()) {
127    llvm::Triple TT(TripleName);
128    TT.setArchName(ArchName);
129    TripleName = TT.str();
130  }
131
132  // Get the target specific parser.
133  std::string Error;
134  const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, Error);
135  if (TheTarget)
136    return TheTarget;
137
138  errs() << ProgName << ": error: unable to get target for '" << TripleName
139         << "', see --version and --triple.\n";
140  return 0;
141}
142
143static tool_output_file *GetOutputStream() {
144  if (OutputFilename == "")
145    OutputFilename = "-";
146
147  std::string Err;
148  tool_output_file *Out = new tool_output_file(OutputFilename.c_str(), Err,
149                                               raw_fd_ostream::F_Binary);
150  if (!Err.empty()) {
151    errs() << Err << '\n';
152    delete Out;
153    return 0;
154  }
155
156  return Out;
157}
158
159static int AsLexInput(const char *ProgName) {
160  std::string ErrorMessage;
161  MemoryBuffer *Buffer = MemoryBuffer::getFileOrSTDIN(InputFilename,
162                                                      &ErrorMessage);
163  if (Buffer == 0) {
164    errs() << ProgName << ": ";
165    if (ErrorMessage.size())
166      errs() << ErrorMessage << "\n";
167    else
168      errs() << "input file didn't read correctly.\n";
169    return 1;
170  }
171
172  SourceMgr SrcMgr;
173
174  // Tell SrcMgr about this buffer, which is what TGParser will pick up.
175  SrcMgr.AddNewSourceBuffer(Buffer, SMLoc());
176
177  // Record the location of the include directories so that the lexer can find
178  // it later.
179  SrcMgr.setIncludeDirs(IncludeDirs);
180
181  const Target *TheTarget = GetTarget(ProgName);
182  if (!TheTarget)
183    return 1;
184
185  llvm::OwningPtr<MCAsmInfo> MAI(TheTarget->createAsmInfo(TripleName));
186  assert(MAI && "Unable to create target asm info!");
187
188  AsmLexer Lexer(*MAI);
189  Lexer.setBuffer(SrcMgr.getMemoryBuffer(0));
190
191  OwningPtr<tool_output_file> Out(GetOutputStream());
192  if (!Out)
193    return 1;
194
195  bool Error = false;
196  while (Lexer.Lex().isNot(AsmToken::Eof)) {
197    switch (Lexer.getKind()) {
198    default:
199      SrcMgr.PrintMessage(Lexer.getLoc(), "unknown token", "warning");
200      Error = true;
201      break;
202    case AsmToken::Error:
203      Error = true; // error already printed.
204      break;
205    case AsmToken::Identifier:
206      Out->os() << "identifier: " << Lexer.getTok().getString() << '\n';
207      break;
208    case AsmToken::String:
209      Out->os() << "string: " << Lexer.getTok().getString() << '\n';
210      break;
211    case AsmToken::Integer:
212      Out->os() << "int: " << Lexer.getTok().getString() << '\n';
213      break;
214
215    case AsmToken::Amp:            Out->os() << "Amp\n"; break;
216    case AsmToken::AmpAmp:         Out->os() << "AmpAmp\n"; break;
217    case AsmToken::Caret:          Out->os() << "Caret\n"; break;
218    case AsmToken::Colon:          Out->os() << "Colon\n"; break;
219    case AsmToken::Comma:          Out->os() << "Comma\n"; break;
220    case AsmToken::Dollar:         Out->os() << "Dollar\n"; break;
221    case AsmToken::EndOfStatement: Out->os() << "EndOfStatement\n"; break;
222    case AsmToken::Eof:            Out->os() << "Eof\n"; break;
223    case AsmToken::Equal:          Out->os() << "Equal\n"; break;
224    case AsmToken::EqualEqual:     Out->os() << "EqualEqual\n"; break;
225    case AsmToken::Exclaim:        Out->os() << "Exclaim\n"; break;
226    case AsmToken::ExclaimEqual:   Out->os() << "ExclaimEqual\n"; break;
227    case AsmToken::Greater:        Out->os() << "Greater\n"; break;
228    case AsmToken::GreaterEqual:   Out->os() << "GreaterEqual\n"; break;
229    case AsmToken::GreaterGreater: Out->os() << "GreaterGreater\n"; break;
230    case AsmToken::LParen:         Out->os() << "LParen\n"; break;
231    case AsmToken::Less:           Out->os() << "Less\n"; break;
232    case AsmToken::LessEqual:      Out->os() << "LessEqual\n"; break;
233    case AsmToken::LessGreater:    Out->os() << "LessGreater\n"; break;
234    case AsmToken::LessLess:       Out->os() << "LessLess\n"; break;
235    case AsmToken::Minus:          Out->os() << "Minus\n"; break;
236    case AsmToken::Percent:        Out->os() << "Percent\n"; break;
237    case AsmToken::Pipe:           Out->os() << "Pipe\n"; break;
238    case AsmToken::PipePipe:       Out->os() << "PipePipe\n"; break;
239    case AsmToken::Plus:           Out->os() << "Plus\n"; break;
240    case AsmToken::RParen:         Out->os() << "RParen\n"; break;
241    case AsmToken::Slash:          Out->os() << "Slash\n"; break;
242    case AsmToken::Star:           Out->os() << "Star\n"; break;
243    case AsmToken::Tilde:          Out->os() << "Tilde\n"; break;
244    }
245  }
246
247  // Keep output if no errors.
248  if (Error == 0) Out->keep();
249
250  return Error;
251}
252
253static int AssembleInput(const char *ProgName) {
254  const Target *TheTarget = GetTarget(ProgName);
255  if (!TheTarget)
256    return 1;
257
258  std::string Error;
259  MemoryBuffer *Buffer = MemoryBuffer::getFileOrSTDIN(InputFilename, &Error);
260  if (Buffer == 0) {
261    errs() << ProgName << ": ";
262    if (Error.size())
263      errs() << Error << "\n";
264    else
265      errs() << "input file didn't read correctly.\n";
266    return 1;
267  }
268
269  SourceMgr SrcMgr;
270
271  // Tell SrcMgr about this buffer, which is what the parser will pick up.
272  SrcMgr.AddNewSourceBuffer(Buffer, SMLoc());
273
274  // Record the location of the include directories so that the lexer can find
275  // it later.
276  SrcMgr.setIncludeDirs(IncludeDirs);
277
278
279  llvm::OwningPtr<MCAsmInfo> MAI(TheTarget->createAsmInfo(TripleName));
280  assert(MAI && "Unable to create target asm info!");
281
282  MCContext Ctx(*MAI);
283
284  // FIXME: We shouldn't need to do this (and link in codegen).
285  OwningPtr<TargetMachine> TM(TheTarget->createTargetMachine(TripleName, ""));
286
287  if (!TM) {
288    errs() << ProgName << ": error: could not create target for triple '"
289           << TripleName << "'.\n";
290    return 1;
291  }
292
293  OwningPtr<tool_output_file> Out(GetOutputStream());
294  if (!Out)
295    return 1;
296
297  formatted_raw_ostream FOS(Out->os());
298  OwningPtr<MCStreamer> Str;
299
300  if (FileType == OFT_AssemblyFile) {
301    MCInstPrinter *IP =
302      TheTarget->createMCInstPrinter(OutputAsmVariant, *MAI);
303    MCCodeEmitter *CE = 0;
304    if (ShowEncoding)
305      CE = TheTarget->createCodeEmitter(*TM, Ctx);
306    Str.reset(createAsmStreamer(Ctx, FOS,
307                                TM->getTargetData()->isLittleEndian(),
308                                /*asmverbose*/true, IP, CE, ShowInst));
309  } else if (FileType == OFT_Null) {
310    Str.reset(createNullStreamer(Ctx));
311  } else {
312    assert(FileType == OFT_ObjectFile && "Invalid file type!");
313    MCCodeEmitter *CE = TheTarget->createCodeEmitter(*TM, Ctx);
314    TargetAsmBackend *TAB = TheTarget->createAsmBackend(TripleName);
315    Str.reset(TheTarget->createObjectStreamer(TripleName, Ctx, *TAB,
316                                              FOS, CE, RelaxAll));
317  }
318
319  if (EnableLogging) {
320    Str.reset(createLoggingStreamer(Str.take(), errs()));
321  }
322
323  OwningPtr<MCAsmParser> Parser(createMCAsmParser(*TheTarget, SrcMgr, Ctx,
324                                                   *Str.get(), *MAI));
325  OwningPtr<TargetAsmParser> TAP(TheTarget->createAsmParser(*Parser, *TM));
326  if (!TAP) {
327    errs() << ProgName
328           << ": error: this target does not support assembly parsing.\n";
329    return 1;
330  }
331
332  Parser->setShowParsedOperands(ShowInstOperands);
333  Parser->setTargetParser(*TAP.get());
334
335  int Res = Parser->Run(NoInitialTextSection);
336
337  // Keep output if no errors.
338  if (Res == 0) Out->keep();
339
340  return Res;
341}
342
343static int DisassembleInput(const char *ProgName, bool Enhanced) {
344  const Target *TheTarget = GetTarget(ProgName);
345  if (!TheTarget)
346    return 0;
347
348  std::string ErrorMessage;
349
350  MemoryBuffer *Buffer = MemoryBuffer::getFileOrSTDIN(InputFilename,
351                                                      &ErrorMessage);
352
353  if (Buffer == 0) {
354    errs() << ProgName << ": ";
355    if (ErrorMessage.size())
356      errs() << ErrorMessage << "\n";
357    else
358      errs() << "input file didn't read correctly.\n";
359    return 1;
360  }
361
362  OwningPtr<tool_output_file> Out(GetOutputStream());
363  if (!Out)
364    return 1;
365
366  int Res;
367  if (Enhanced)
368    Res = Disassembler::disassembleEnhanced(TripleName, *Buffer, Out->os());
369  else
370    Res = Disassembler::disassemble(*TheTarget, TripleName, *Buffer, Out->os());
371
372  // Keep output if no errors.
373  if (Res == 0) Out->keep();
374
375  return Res;
376}
377
378
379int main(int argc, char **argv) {
380  // Print a stack trace if we signal out.
381  sys::PrintStackTraceOnErrorSignal();
382  PrettyStackTraceProgram X(argc, argv);
383  llvm_shutdown_obj Y;  // Call llvm_shutdown() on exit.
384
385  // Initialize targets and assembly printers/parsers.
386  llvm::InitializeAllTargetInfos();
387  // FIXME: We shouldn't need to initialize the Target(Machine)s.
388  llvm::InitializeAllTargets();
389  llvm::InitializeAllAsmPrinters();
390  llvm::InitializeAllAsmParsers();
391  llvm::InitializeAllDisassemblers();
392
393  cl::ParseCommandLineOptions(argc, argv, "llvm machine code playground\n");
394  TripleName = Triple::normalize(TripleName);
395
396  switch (Action) {
397  default:
398  case AC_AsLex:
399    return AsLexInput(argv[0]);
400  case AC_Assemble:
401    return AssembleInput(argv[0]);
402  case AC_Disassemble:
403    return DisassembleInput(argv[0], false);
404  case AC_EDisassemble:
405    return DisassembleInput(argv[0], true);
406  }
407
408  return 0;
409}
410
411