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