a8b6bed223
all of the features in the current working draft of the upcoming C++ standard, provisionally named C++1y. The code generator's performance is greatly increased, and the loop auto-vectorizer is now enabled at -Os and -O2 in addition to -O3. The PowerPC backend has made several major improvements to code generation quality and compile time, and the X86, SPARC, ARM32, Aarch64 and SystemZ backends have all seen major feature work. Release notes for llvm and clang can be found here: <http://llvm.org/releases/3.4/docs/ReleaseNotes.html> <http://llvm.org/releases/3.4/tools/clang/docs/ReleaseNotes.html> MFC after: 1 month
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/OwningPtr.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) {
|
|
// 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);
|
|
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) {
|
|
OwningPtr<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);
|
|
}
|
|
|
|
if (InAtomicBlock) {
|
|
SM.PrintMessage(SMLoc::getFromPointer(Str.data()), SourceMgr::DK_Error,
|
|
"unclosed atomic block");
|
|
ErrorOccurred = true;
|
|
}
|
|
|
|
return ErrorOccurred;
|
|
}
|