mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-10 02:36:06 +00:00
508bd63046
This patch re-introduces the MCContext member that was removed from MCDisassembler in r206063, and requires that an MCContext be passed in at MCDisassembler construction time. (Previously the MCContext member had been initialized in an ad-hoc fashion after construction). The MCCContext member can be used by MCDisassembler sub-classes to construct constant or target-specific MCExprs. This patch updates disassemblers for in-tree targets, and provides the MCRegisterInfo instance that some disassemblers were using through the MCContext (previously those backends were constructing their own MCRegisterInfo instances). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@206241 91177308-0d34-0410-b5e6-96231b3b80d8
236 lines
7.0 KiB
C++
236 lines
7.0 KiB
C++
//===- Disassembler.cpp - Disassembler for hex strings --------------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This class implements the disassembler of strings of bytes written in
|
|
// hexadecimal, from standard input or from a file.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "Disassembler.h"
|
|
#include "llvm/ADT/Triple.h"
|
|
#include "llvm/MC/MCAsmInfo.h"
|
|
#include "llvm/MC/MCContext.h"
|
|
#include "llvm/MC/MCDisassembler.h"
|
|
#include "llvm/MC/MCInst.h"
|
|
#include "llvm/MC/MCRegisterInfo.h"
|
|
#include "llvm/MC/MCStreamer.h"
|
|
#include "llvm/MC/MCSubtargetInfo.h"
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
#include "llvm/Support/MemoryObject.h"
|
|
#include "llvm/Support/SourceMgr.h"
|
|
#include "llvm/Support/TargetRegistry.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
using namespace llvm;
|
|
|
|
typedef std::vector<std::pair<unsigned char, const char*> > ByteArrayTy;
|
|
|
|
namespace {
|
|
class VectorMemoryObject : public MemoryObject {
|
|
private:
|
|
const ByteArrayTy &Bytes;
|
|
public:
|
|
VectorMemoryObject(const ByteArrayTy &bytes) : Bytes(bytes) {}
|
|
|
|
uint64_t getBase() const override { return 0; }
|
|
uint64_t getExtent() const override { return Bytes.size(); }
|
|
|
|
int readByte(uint64_t Addr, uint8_t *Byte) const override {
|
|
if (Addr >= getExtent())
|
|
return -1;
|
|
*Byte = Bytes[Addr].first;
|
|
return 0;
|
|
}
|
|
};
|
|
}
|
|
|
|
static bool PrintInsts(const MCDisassembler &DisAsm,
|
|
const ByteArrayTy &Bytes,
|
|
SourceMgr &SM, raw_ostream &Out,
|
|
MCStreamer &Streamer, bool InAtomicBlock,
|
|
const MCSubtargetInfo &STI) {
|
|
// Wrap the vector in a MemoryObject.
|
|
VectorMemoryObject memoryObject(Bytes);
|
|
|
|
// Disassemble it to strings.
|
|
uint64_t Size;
|
|
uint64_t Index;
|
|
|
|
for (Index = 0; Index < Bytes.size(); Index += Size) {
|
|
MCInst Inst;
|
|
|
|
MCDisassembler::DecodeStatus S;
|
|
S = DisAsm.getInstruction(Inst, Size, memoryObject, Index,
|
|
/*REMOVE*/ nulls(), nulls());
|
|
switch (S) {
|
|
case MCDisassembler::Fail:
|
|
SM.PrintMessage(SMLoc::getFromPointer(Bytes[Index].second),
|
|
SourceMgr::DK_Warning,
|
|
"invalid instruction encoding");
|
|
// Don't try to resynchronise the stream in a block
|
|
if (InAtomicBlock)
|
|
return true;
|
|
|
|
if (Size == 0)
|
|
Size = 1; // skip illegible bytes
|
|
|
|
break;
|
|
|
|
case MCDisassembler::SoftFail:
|
|
SM.PrintMessage(SMLoc::getFromPointer(Bytes[Index].second),
|
|
SourceMgr::DK_Warning,
|
|
"potentially undefined instruction encoding");
|
|
// Fall through
|
|
|
|
case MCDisassembler::Success:
|
|
Streamer.EmitInstruction(Inst, STI);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool SkipToToken(StringRef &Str) {
|
|
while (!Str.empty() && Str.find_first_not_of(" \t\r\n#,") != 0) {
|
|
// Strip horizontal whitespace and commas.
|
|
if (size_t Pos = Str.find_first_not_of(" \t\r,")) {
|
|
Str = Str.substr(Pos);
|
|
}
|
|
|
|
// If this is the end of a line or start of a comment, remove the rest of
|
|
// the line.
|
|
if (Str[0] == '\n' || Str[0] == '#') {
|
|
// Strip to the end of line if we already processed any bytes on this
|
|
// line. This strips the comment and/or the \n.
|
|
if (Str[0] == '\n') {
|
|
Str = Str.substr(1);
|
|
} else {
|
|
Str = Str.substr(Str.find_first_of('\n'));
|
|
if (!Str.empty())
|
|
Str = Str.substr(1);
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
|
|
return !Str.empty();
|
|
}
|
|
|
|
|
|
static bool ByteArrayFromString(ByteArrayTy &ByteArray,
|
|
StringRef &Str,
|
|
SourceMgr &SM) {
|
|
while (SkipToToken(Str)) {
|
|
// Handled by higher level
|
|
if (Str[0] == '[' || Str[0] == ']')
|
|
return false;
|
|
|
|
// Get the current token.
|
|
size_t Next = Str.find_first_of(" \t\n\r,#[]");
|
|
StringRef Value = Str.substr(0, Next);
|
|
|
|
// Convert to a byte and add to the byte vector.
|
|
unsigned ByteVal;
|
|
if (Value.getAsInteger(0, ByteVal) || ByteVal > 255) {
|
|
// If we have an error, print it and skip to the end of line.
|
|
SM.PrintMessage(SMLoc::getFromPointer(Value.data()), SourceMgr::DK_Error,
|
|
"invalid input token");
|
|
Str = Str.substr(Str.find('\n'));
|
|
ByteArray.clear();
|
|
continue;
|
|
}
|
|
|
|
ByteArray.push_back(std::make_pair((unsigned char)ByteVal, Value.data()));
|
|
Str = Str.substr(Next);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
int Disassembler::disassemble(const Target &T,
|
|
const std::string &Triple,
|
|
MCSubtargetInfo &STI,
|
|
MCStreamer &Streamer,
|
|
MemoryBuffer &Buffer,
|
|
SourceMgr &SM,
|
|
raw_ostream &Out) {
|
|
|
|
std::unique_ptr<const MCRegisterInfo> MRI(T.createMCRegInfo(Triple));
|
|
if (!MRI) {
|
|
errs() << "error: no register info for target " << Triple << "\n";
|
|
return -1;
|
|
}
|
|
|
|
std::unique_ptr<const MCAsmInfo> MAI(T.createMCAsmInfo(*MRI, Triple));
|
|
if (!MAI) {
|
|
errs() << "error: no assembly info for target " << Triple << "\n";
|
|
return -1;
|
|
}
|
|
|
|
// Set up the MCContext for creating symbols and MCExpr's.
|
|
MCContext Ctx(MAI.get(), MRI.get(), 0);
|
|
|
|
std::unique_ptr<const MCDisassembler> DisAsm(
|
|
T.createMCDisassembler(STI, Ctx));
|
|
if (!DisAsm) {
|
|
errs() << "error: no disassembler for target " << Triple << "\n";
|
|
return -1;
|
|
}
|
|
|
|
// Set up initial section manually here
|
|
Streamer.InitSections();
|
|
|
|
bool ErrorOccurred = false;
|
|
|
|
// Convert the input to a vector for disassembly.
|
|
ByteArrayTy ByteArray;
|
|
StringRef Str = Buffer.getBuffer();
|
|
bool InAtomicBlock = false;
|
|
|
|
while (SkipToToken(Str)) {
|
|
ByteArray.clear();
|
|
|
|
if (Str[0] == '[') {
|
|
if (InAtomicBlock) {
|
|
SM.PrintMessage(SMLoc::getFromPointer(Str.data()), SourceMgr::DK_Error,
|
|
"nested atomic blocks make no sense");
|
|
ErrorOccurred = true;
|
|
}
|
|
InAtomicBlock = true;
|
|
Str = Str.drop_front();
|
|
continue;
|
|
} else if (Str[0] == ']') {
|
|
if (!InAtomicBlock) {
|
|
SM.PrintMessage(SMLoc::getFromPointer(Str.data()), SourceMgr::DK_Error,
|
|
"attempt to close atomic block without opening");
|
|
ErrorOccurred = true;
|
|
}
|
|
InAtomicBlock = false;
|
|
Str = Str.drop_front();
|
|
continue;
|
|
}
|
|
|
|
// It's a real token, get the bytes and emit them
|
|
ErrorOccurred |= ByteArrayFromString(ByteArray, Str, SM);
|
|
|
|
if (!ByteArray.empty())
|
|
ErrorOccurred |= PrintInsts(*DisAsm, ByteArray, SM, Out, Streamer,
|
|
InAtomicBlock, STI);
|
|
}
|
|
|
|
if (InAtomicBlock) {
|
|
SM.PrintMessage(SMLoc::getFromPointer(Str.data()), SourceMgr::DK_Error,
|
|
"unclosed atomic block");
|
|
ErrorOccurred = true;
|
|
}
|
|
|
|
return ErrorOccurred;
|
|
}
|