81a0045897a20dedd38a4fea338d0bcfa6d2aca7
[oota-llvm.git] / tools / llvm-mc / Disassembler.cpp
1 //===- Disassembler.cpp - Disassembler for hex strings --------------------===//
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 class implements the disassembler of strings of bytes written in
11 // hexadecimal, from standard input or from a file.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #include "Disassembler.h"
16 #include "llvm/ADT/OwningPtr.h"
17 #include "llvm/ADT/Triple.h"
18 #include "llvm/MC/MCDisassembler.h"
19 #include "llvm/MC/MCInst.h"
20 #include "llvm/MC/MCStreamer.h"
21 #include "llvm/MC/MCSubtargetInfo.h"
22 #include "llvm/Support/MemoryBuffer.h"
23 #include "llvm/Support/MemoryObject.h"
24 #include "llvm/Support/SourceMgr.h"
25 #include "llvm/Support/TargetRegistry.h"
26 #include "llvm/Support/raw_ostream.h"
27
28 using namespace llvm;
29
30 typedef std::vector<std::pair<unsigned char, const char*> > ByteArrayTy;
31
32 namespace {
33 class VectorMemoryObject : public MemoryObject {
34 private:
35   const ByteArrayTy &Bytes;
36 public:
37   VectorMemoryObject(const ByteArrayTy &bytes) : Bytes(bytes) {}
38
39   uint64_t getBase() const { return 0; }
40   uint64_t getExtent() const { return Bytes.size(); }
41
42   int readByte(uint64_t Addr, uint8_t *Byte) const {
43     if (Addr >= getExtent())
44       return -1;
45     *Byte = Bytes[Addr].first;
46     return 0;
47   }
48 };
49 }
50
51 static bool PrintInsts(const MCDisassembler &DisAsm,
52                        const ByteArrayTy &Bytes,
53                        SourceMgr &SM, raw_ostream &Out,
54                        MCStreamer &Streamer, bool InAtomicBlock) {
55   // Wrap the vector in a MemoryObject.
56   VectorMemoryObject memoryObject(Bytes);
57
58   // Disassemble it to strings.
59   uint64_t Size;
60   uint64_t Index;
61
62   for (Index = 0; Index < Bytes.size(); Index += Size) {
63     MCInst Inst;
64
65     MCDisassembler::DecodeStatus S;
66     S = DisAsm.getInstruction(Inst, Size, memoryObject, Index,
67                               /*REMOVE*/ nulls(), nulls());
68     switch (S) {
69     case MCDisassembler::Fail:
70       SM.PrintMessage(SMLoc::getFromPointer(Bytes[Index].second),
71                       SourceMgr::DK_Warning,
72                       "invalid instruction encoding");
73       // Don't try to resynchronise the stream in a block
74       if (InAtomicBlock)
75         return true;
76
77       if (Size == 0)
78         Size = 1; // skip illegible bytes
79
80       break;
81
82     case MCDisassembler::SoftFail:
83       SM.PrintMessage(SMLoc::getFromPointer(Bytes[Index].second),
84                       SourceMgr::DK_Warning,
85                       "potentially undefined instruction encoding");
86       // Fall through
87
88     case MCDisassembler::Success:
89       Streamer.EmitInstruction(Inst);
90       break;
91     }
92   }
93
94   return false;
95 }
96
97 static bool SkipToToken(StringRef &Str) {
98   while (!Str.empty() && Str.find_first_not_of(" \t\r\n#,") != 0) {
99     // Strip horizontal whitespace and commas.
100     if (size_t Pos = Str.find_first_not_of(" \t\r,")) {
101       Str = Str.substr(Pos);
102     }
103
104     // If this is the end of a line or start of a comment, remove the rest of
105     // the line.
106     if (Str[0] == '\n' || Str[0] == '#') {
107       // Strip to the end of line if we already processed any bytes on this
108       // line.  This strips the comment and/or the \n.
109       if (Str[0] == '\n') {
110         Str = Str.substr(1);
111       } else {
112         Str = Str.substr(Str.find_first_of('\n'));
113         if (!Str.empty())
114           Str = Str.substr(1);
115       }
116       continue;
117     }
118   }
119
120   return !Str.empty();
121 }
122
123
124 static bool ByteArrayFromString(ByteArrayTy &ByteArray,
125                                 StringRef &Str,
126                                 SourceMgr &SM) {
127   while (SkipToToken(Str)) {
128     // Handled by higher level
129     if (Str[0] == '[' || Str[0] == ']')
130       return false;
131
132     // Get the current token.
133     size_t Next = Str.find_first_of(" \t\n\r,#[]");
134     StringRef Value = Str.substr(0, Next);
135
136     // Convert to a byte and add to the byte vector.
137     unsigned ByteVal;
138     if (Value.getAsInteger(0, ByteVal) || ByteVal > 255) {
139       // If we have an error, print it and skip to the end of line.
140       SM.PrintMessage(SMLoc::getFromPointer(Value.data()), SourceMgr::DK_Error,
141                       "invalid input token");
142       Str = Str.substr(Str.find('\n'));
143       ByteArray.clear();
144       continue;
145     }
146
147     ByteArray.push_back(std::make_pair((unsigned char)ByteVal, Value.data()));
148     Str = Str.substr(Next);
149   }
150
151   return false;
152 }
153
154 int Disassembler::disassemble(const Target &T,
155                               const std::string &Triple,
156                               MCSubtargetInfo &STI,
157                               MCStreamer &Streamer,
158                               MemoryBuffer &Buffer,
159                               SourceMgr &SM,
160                               raw_ostream &Out) {
161   OwningPtr<const MCDisassembler> DisAsm(T.createMCDisassembler(STI));
162   if (!DisAsm) {
163     errs() << "error: no disassembler for target " << Triple << "\n";
164     return -1;
165   }
166
167   // Set up initial section manually here
168   Streamer.InitSections();
169
170   bool ErrorOccurred = false;
171
172   // Convert the input to a vector for disassembly.
173   ByteArrayTy ByteArray;
174   StringRef Str = Buffer.getBuffer();
175   bool InAtomicBlock = false;
176
177   while (SkipToToken(Str)) {
178     ByteArray.clear();
179
180     if (Str[0] == '[') {
181       if (InAtomicBlock) {
182         SM.PrintMessage(SMLoc::getFromPointer(Str.data()), SourceMgr::DK_Error,
183                         "nested atomic blocks make no sense");
184         ErrorOccurred = true;
185       }
186       InAtomicBlock = true;
187       Str = Str.drop_front();
188       continue;
189     } else if (Str[0] == ']') {
190       if (!InAtomicBlock) {
191         SM.PrintMessage(SMLoc::getFromPointer(Str.data()), SourceMgr::DK_Error,
192                         "attempt to close atomic block without opening");
193         ErrorOccurred = true;
194       }
195       InAtomicBlock = false;
196       Str = Str.drop_front();
197       continue;
198     }
199
200     // It's a real token, get the bytes and emit them
201     ErrorOccurred |= ByteArrayFromString(ByteArray, Str, SM);
202
203     if (!ByteArray.empty())
204       ErrorOccurred |= PrintInsts(*DisAsm, ByteArray, SM, Out, Streamer,
205                                   InAtomicBlock);
206   }
207
208   if (InAtomicBlock) {
209     SM.PrintMessage(SMLoc::getFromPointer(Str.data()), SourceMgr::DK_Error,
210                     "unclosed atomic block");
211     ErrorOccurred = true;
212   }
213
214   return ErrorOccurred;
215 }