brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.8 KiB · 9a61f68 Raw
241 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/ADT/StringExtras.h"16#include "llvm/MC/MCAsmInfo.h"17#include "llvm/MC/MCContext.h"18#include "llvm/MC/MCDisassembler/MCDisassembler.h"19#include "llvm/MC/MCInst.h"20#include "llvm/MC/MCObjectFileInfo.h"21#include "llvm/MC/MCRegisterInfo.h"22#include "llvm/MC/MCStreamer.h"23#include "llvm/MC/MCSubtargetInfo.h"24#include "llvm/MC/TargetRegistry.h"25#include "llvm/Support/MemoryBuffer.h"26#include "llvm/Support/SourceMgr.h"27#include "llvm/Support/TimeProfiler.h"28#include "llvm/Support/raw_ostream.h"29#include "llvm/TargetParser/Triple.h"30 31using namespace llvm;32 33typedef std::pair<std::vector<unsigned char>, std::vector<const char *>>34    ByteArrayTy;35 36static MCDisassembler::DecodeStatus getInstruction(const MCDisassembler &DisAsm,37                                                   const MCSubtargetInfo &STI,38                                                   MCInst &Inst, uint64_t &Size,39                                                   ArrayRef<uint8_t> Bytes,40                                                   uint64_t Address) {41  if (STI.getTargetTriple().getArch() == Triple::hexagon)42    return DisAsm.getInstructionBundle(Inst, Size, Bytes, Address, nulls());43  return DisAsm.getInstruction(Inst, Size, Bytes, Address, nulls());44}45 46static bool printInsts(const MCDisassembler &DisAsm, const ByteArrayTy &Bytes,47                       SourceMgr &SM, MCStreamer &Streamer, bool InAtomicBlock,48                       const MCSubtargetInfo &STI, unsigned NumBenchmarkRuns) {49  ArrayRef<uint8_t> Data(Bytes.first);50 51  // Disassemble it to strings.52  uint64_t Size;53 54  for (uint64_t Index = 0; Index < Bytes.first.size(); Index += Size) {55 56    MCInst Inst;57    MCDisassembler::DecodeStatus S =58        getInstruction(DisAsm, STI, Inst, Size, Data.slice(Index), Index);59    switch (S) {60    case MCDisassembler::Fail:61      SM.PrintMessage(SMLoc::getFromPointer(Bytes.second[Index]),62                      SourceMgr::DK_Warning,63                      "invalid instruction encoding");64      // Don't try to resynchronise the stream in a block65      if (InAtomicBlock)66        return true;67 68      if (Size == 0)69        Size = 1; // skip illegible bytes70 71      break;72 73    case MCDisassembler::SoftFail:74      SM.PrintMessage(SMLoc::getFromPointer(Bytes.second[Index]),75                      SourceMgr::DK_Warning,76                      "potentially undefined instruction encoding");77      [[fallthrough]];78 79    case MCDisassembler::Success:80      Streamer.emitInstruction(Inst, STI);81      break;82    }83 84    if (S == MCDisassembler::Success && NumBenchmarkRuns != 0) {85      // Benchmark mode, collect timing for decoding the instruction several86      // times.87      MCInst BMInst;88      TimeTraceScope timeScope("getInstruction");89      for (unsigned I = 0; I < NumBenchmarkRuns; ++I) {90        BMInst.clear();91        BMInst.setOpcode(0);92        S = getInstruction(DisAsm, STI, BMInst, Size, Data.slice(Index), Index);93      }94    }95  }96 97  return false;98}99 100static bool SkipToToken(StringRef &Str) {101  for (;;) {102    if (Str.empty())103      return false;104 105    // Strip horizontal whitespace and commas.106    if (size_t Pos = Str.find_first_not_of(" \t\r\n,")) {107      Str = Str.substr(Pos);108      continue;109    }110 111    // If this is the start of a comment, remove the rest of the line.112    if (Str[0] == '#') {113        Str = Str.substr(Str.find_first_of('\n'));114      continue;115    }116    return true;117  }118}119 120static bool byteArrayFromString(ByteArrayTy &ByteArray, StringRef &Str,121                                SourceMgr &SM, bool HexBytes) {122  while (SkipToToken(Str)) {123    // Handled by higher level124    if (Str[0] == '[' || Str[0] == ']')125      return false;126 127    // Get the current token.128    size_t Next = Str.find_first_of(" \t\n\r,#[]");129    StringRef Value = Str.substr(0, Next);130 131    // Convert to a byte and add to the byte vector.132    unsigned ByteVal;133    if (HexBytes) {134      if (Next < 2) {135        SM.PrintMessage(SMLoc::getFromPointer(Value.data()),136                        SourceMgr::DK_Error, "expected two hex digits");137        Str = Str.substr(Next);138        return true;139      }140      Next = 2;141      unsigned C0 = hexDigitValue(Value[0]);142      unsigned C1 = hexDigitValue(Value[1]);143      if (C0 == -1u || C1 == -1u) {144        SM.PrintMessage(SMLoc::getFromPointer(Value.data()),145                        SourceMgr::DK_Error, "invalid input token");146        Str = Str.substr(Next);147        return true;148      }149      ByteVal = C0 * 16 + C1;150    } else if (Value.getAsInteger(0, ByteVal) || ByteVal > 255) {151      // If we have an error, print it and skip to the end of line.152      SM.PrintMessage(SMLoc::getFromPointer(Value.data()), SourceMgr::DK_Error,153                      "invalid input token");154      Str = Str.substr(Str.find('\n'));155      ByteArray.first.clear();156      ByteArray.second.clear();157      continue;158    }159 160    ByteArray.first.push_back(ByteVal);161    ByteArray.second.push_back(Value.data());162    Str = Str.substr(Next);163  }164 165  return false;166}167 168int Disassembler::disassemble(const Target &T, MCSubtargetInfo &STI,169                              MCStreamer &Streamer, MemoryBuffer &Buffer,170                              SourceMgr &SM, MCContext &Ctx,171                              const MCTargetOptions &MCOptions, bool HexBytes,172                              unsigned NumBenchmarkRuns) {173  const Triple &TheTriple = STI.getTargetTriple();174  std::unique_ptr<const MCRegisterInfo> MRI(T.createMCRegInfo(TheTriple));175  if (!MRI) {176    errs() << "error: no register info for target " << TheTriple.str() << '\n';177    return -1;178  }179 180  std::unique_ptr<const MCAsmInfo> MAI(181      T.createMCAsmInfo(*MRI, TheTriple, MCOptions));182  if (!MAI) {183    errs() << "error: no assembly info for target " << TheTriple.str() << '\n';184    return -1;185  }186 187  std::unique_ptr<const MCDisassembler> DisAsm(188    T.createMCDisassembler(STI, Ctx));189  if (!DisAsm) {190    errs() << "error: no disassembler for target " << TheTriple.str() << '\n';191    return -1;192  }193 194  bool ErrorOccurred = false;195 196  // Convert the input to a vector for disassembly.197  ByteArrayTy ByteArray;198  StringRef Str = Buffer.getBuffer();199  bool InAtomicBlock = false;200 201  while (SkipToToken(Str)) {202    ByteArray.first.clear();203    ByteArray.second.clear();204 205    if (Str[0] == '[') {206      if (InAtomicBlock) {207        SM.PrintMessage(SMLoc::getFromPointer(Str.data()), SourceMgr::DK_Error,208                        "nested atomic blocks make no sense");209        ErrorOccurred = true;210      }211      InAtomicBlock = true;212      Str = Str.drop_front();213      continue;214    } else if (Str[0] == ']') {215      if (!InAtomicBlock) {216        SM.PrintMessage(SMLoc::getFromPointer(Str.data()), SourceMgr::DK_Error,217                        "attempt to close atomic block without opening");218        ErrorOccurred = true;219      }220      InAtomicBlock = false;221      Str = Str.drop_front();222      continue;223    }224 225    // It's a real token, get the bytes and emit them226    ErrorOccurred |= byteArrayFromString(ByteArray, Str, SM, HexBytes);227 228    if (!ByteArray.first.empty())229      ErrorOccurred |= printInsts(*DisAsm, ByteArray, SM, Streamer,230                                  InAtomicBlock, STI, NumBenchmarkRuns);231  }232 233  if (InAtomicBlock) {234    SM.PrintMessage(SMLoc::getFromPointer(Str.data()), SourceMgr::DK_Error,235                    "unclosed atomic block");236    ErrorOccurred = true;237  }238 239  return ErrorOccurred;240}241