mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-04 21:30:49 +00:00
f4ccd11075
This compiles with no changes to clang/lld/lldb with MSVC and includes overloads to various functions which are used by those projects and llvm which have OwningPtr's as parameters. This should allow out of tree projects some time to move. There are also no changes to libs/Target, which should help out of tree targets have time to move, if necessary. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@203083 91177308-0d34-0410-b5e6-96231b3b80d8
216 lines
6.4 KiB
C++
216 lines
6.4 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/MCDisassembler.h"
|
|
#include "llvm/MC/MCInst.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 { return 0; }
|
|
uint64_t getExtent() const { return Bytes.size(); }
|
|
|
|
int readByte(uint64_t Addr, uint8_t *Byte) const {
|
|
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 MCDisassembler> DisAsm(T.createMCDisassembler(STI));
|
|
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;
|
|
}
|