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