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