From 668b15467be158a5f0e0c4a5e1ec232da021892c Mon Sep 17 00:00:00 2001 From: Sean Callanan Date: Mon, 12 Apr 2010 19:43:00 +0000 Subject: [PATCH] Second try at integrating the edis tester. This time I use the LIBS variable, which is not subject to a %.a -> -l% transformation, to link llvm-mc against libEnhancedDisassembly. llvm-mc -edis works the same as llvm-mc -disassemble, but outputs tokens and operands. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@101058 91177308-0d34-0410-b5e6-96231b3b80d8 --- tools/Makefile | 2 + tools/llvm-mc/Disassembler.cpp | 283 ++++++++++++++++++++++++++++----- tools/llvm-mc/Disassembler.h | 3 + tools/llvm-mc/Makefile | 3 + tools/llvm-mc/llvm-mc.cpp | 16 +- 5 files changed, 259 insertions(+), 48 deletions(-) diff --git a/tools/Makefile b/tools/Makefile index 8205568c2f5..c2b12e72117 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -36,6 +36,8 @@ include $(LEVEL)/Makefile.config ifeq ($(ENABLE_PIC),1) # No support for dynamic libraries on windows targets. ifneq ($(TARGET_OS), $(filter $(TARGET_OS), Cygwin MingW)) + # libEnhancedDisassembly must be built ahead of llvm-mc + # because llvm-mc links against libEnhancedDisassembly DIRS += edis # gold only builds if binutils is around. It requires "lto" to build before diff --git a/tools/llvm-mc/Disassembler.cpp b/tools/llvm-mc/Disassembler.cpp index 9fe07909284..4a63e99a6e7 100644 --- a/tools/llvm-mc/Disassembler.cpp +++ b/tools/llvm-mc/Disassembler.cpp @@ -15,6 +15,7 @@ #include "Disassembler.h" #include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/Triple.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCDisassembler.h" #include "llvm/MC/MCInst.h" @@ -24,6 +25,9 @@ #include "llvm/Support/MemoryObject.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/SourceMgr.h" + +#include "llvm-c/EnhancedDisassembly.h" + using namespace llvm; typedef std::vector > ByteArrayTy; @@ -64,8 +68,7 @@ static bool PrintInsts(const MCDisassembler &DisAsm, /*REMOVE*/ nulls())) { Printer.printInst(&Inst, outs()); outs() << "\n"; - } - else { + } else { SM.PrintMessage(SMLoc::getFromPointer(Bytes[Index].second), "invalid instruction encoding", "warning"); if (Size == 0) @@ -76,6 +79,53 @@ static bool PrintInsts(const MCDisassembler &DisAsm, return false; } +static bool ByteArrayFromString(ByteArrayTy &ByteArray, + StringRef &Str, + SourceMgr &SM) { + while (!Str.empty()) { + // Strip horizontal whitespace. + if (size_t Pos = Str.find_first_not_of(" \t\r")) { + Str = Str.substr(Pos); + continue; + } + + // 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; + } + + // 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()), + "invalid input token", "error"); + 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, MemoryBuffer &Buffer) { // Set up disassembler. @@ -105,52 +155,197 @@ int Disassembler::disassemble(const Target &T, const std::string &Triple, // Convert the input to a vector for disassembly. ByteArrayTy ByteArray; - StringRef Str = Buffer.getBuffer(); - while (!Str.empty()) { - // Strip horizontal whitespace. - if (size_t Pos = Str.find_first_not_of(" \t\r")) { - Str = Str.substr(Pos); - continue; - } - - // 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; - } - - // 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()), - "invalid input token", "error"); - ErrorOccurred = true; - Str = Str.substr(Str.find('\n')); - ByteArray.clear(); - continue; - } - - ByteArray.push_back(std::make_pair((unsigned char)ByteVal, Value.data())); - Str = Str.substr(Next); - } + + ErrorOccurred |= ByteArrayFromString(ByteArray, Str, SM); if (!ByteArray.empty()) ErrorOccurred |= PrintInsts(*DisAsm, *IP, ByteArray, SM); return ErrorOccurred; } + +static int byteArrayReader(uint8_t *B, uint64_t A, void *Arg) { + ByteArrayTy &ByteArray = *((ByteArrayTy*)Arg); + + if (A >= ByteArray.size()) + return -1; + + *B = ByteArray[A].first; + + return 0; +} + +static int verboseEvaluator(uint64_t *V, unsigned R, void *Arg) { + EDDisassemblerRef &disassembler = *((EDDisassemblerRef*)Arg); + + const char *regName; + + if (!EDGetRegisterName(®Name, + disassembler, + R)) + outs() << "[" << regName << "/" << R << "]"; + if (EDRegisterIsStackPointer(disassembler, R)) + outs() << "(sp)"; + if (EDRegisterIsProgramCounter(disassembler, R)) + outs() << "(pc)"; + + *V = 0; + + return 0; +} + +int Disassembler::disassembleEnhanced(const std::string &TS, + MemoryBuffer &Buffer) { + ByteArrayTy ByteArray; + StringRef Str = Buffer.getBuffer(); + SourceMgr SM; + + SM.AddNewSourceBuffer(&Buffer, SMLoc()); + + if (ByteArrayFromString(ByteArray, Str, SM)) { + return -1; + } + + EDDisassemblerRef disassembler; + + Triple T(TS); + EDAssemblySyntax_t AS; + + switch (T.getArch()) { + default: + errs() << "error: no default assembly syntax for " << TS.c_str() << "\n"; + return -1; + case Triple::arm: + case Triple::thumb: + AS = kEDAssemblySyntaxARMUAL; + break; + case Triple::x86: + case Triple::x86_64: + AS = kEDAssemblySyntaxX86ATT; + break; + } + + if (EDGetDisassembler(&disassembler, + TS.c_str(), + AS)) { + errs() << "error: couldn't get disassembler for " << TS.c_str() << "\n"; + return -1; + } + + EDInstRef inst; + + if (EDCreateInsts(&inst, 1, disassembler, byteArrayReader, 0,&ByteArray) + != 1) { + errs() << "error: Didn't get an instruction\n"; + return -1; + } + + int numTokens = EDNumTokens(inst); + + if (numTokens < 0) { + errs() << "error: Couldn't count the instruction's tokens\n"; + return -1; + } + + int tokenIndex; + + for (tokenIndex = 0; tokenIndex < numTokens; ++tokenIndex) { + EDTokenRef token; + + if (EDGetToken(&token, inst, tokenIndex)) { + errs() << "error: Couldn't get token\n"; + return -1; + } + + const char *buf; + + if (EDGetTokenString(&buf, token)) { + errs() << "error: Couldn't get string for token\n"; + return -1; + } + + outs() << "["; + + int operandIndex = EDOperandIndexForToken(token); + + if (operandIndex >= 0) + outs() << operandIndex << "-"; + + if (EDTokenIsWhitespace(token)) { + outs() << "w"; + } else if (EDTokenIsPunctuation(token)) { + outs() << "p"; + } else if (EDTokenIsOpcode(token)) { + outs() << "o"; + } else if (EDTokenIsLiteral(token)) { + outs() << "l"; + } else if (EDTokenIsRegister(token)) { + outs() << "r"; + } else { + outs() << "?"; + } + + outs() << ":" << buf; + + if (EDTokenIsLiteral(token)) { + outs() << "="; + if (EDTokenIsNegativeLiteral(token)) + outs() << "-"; + uint64_t absoluteValue; + if (EDLiteralTokenAbsoluteValue(&absoluteValue, token)) { + errs() << "error: Couldn't get the value of a literal token\n"; + return -1; + } + outs() << absoluteValue; + } else if (EDTokenIsRegister(token)) { + outs() << "="; + unsigned regID; + if (EDRegisterTokenValue(®ID, token)) { + errs() << "error: Couldn't get the ID of a register token\n"; + return -1; + } + outs() << "r" << regID; + } + + outs() << "]"; + } + + outs() << " "; + + int numOperands = EDNumOperands(inst); + + if (numOperands < 0) { + errs() << "error: Couldn't count operands\n"; + return -1; + } + + int operandIndex; + + for (operandIndex = 0; operandIndex < numOperands; ++operandIndex) { + outs() << operandIndex << ":"; + + EDOperandRef operand; + + if (EDGetOperand(&operand, + inst, + operandIndex)) { + errs() << "error: Couldn't get operand\n"; + return -1; + } + + uint64_t evaluatedResult; + + EDEvaluateOperand(&evaluatedResult, + operand, + verboseEvaluator, + &disassembler); + + outs() << " "; + } + + outs() << "\n"; + + return 0; +} + diff --git a/tools/llvm-mc/Disassembler.h b/tools/llvm-mc/Disassembler.h index 78c2f854946..3da23965bdb 100644 --- a/tools/llvm-mc/Disassembler.h +++ b/tools/llvm-mc/Disassembler.h @@ -27,6 +27,9 @@ public: static int disassemble(const Target &target, const std::string &tripleString, MemoryBuffer &buffer); + + static int disassembleEnhanced(const std::string &tripleString, + MemoryBuffer &buffer); }; } // namespace llvm diff --git a/tools/llvm-mc/Makefile b/tools/llvm-mc/Makefile index 5b0fe3f5446..f92e643c332 100644 --- a/tools/llvm-mc/Makefile +++ b/tools/llvm-mc/Makefile @@ -22,3 +22,6 @@ include $(LEVEL)/Makefile.config LINK_COMPONENTS := $(TARGETS_TO_BUILD) MCParser MC support include $(LLVM_SRC_ROOT)/Makefile.rules + +# Using LIBS instead of USEDLIBS to force static linking +LIBS += $(LLVMLibDir)/libEnhancedDisassembly.a diff --git a/tools/llvm-mc/llvm-mc.cpp b/tools/llvm-mc/llvm-mc.cpp index c6657f5d3e7..47f67c5e1bb 100644 --- a/tools/llvm-mc/llvm-mc.cpp +++ b/tools/llvm-mc/llvm-mc.cpp @@ -97,7 +97,8 @@ NoInitialTextSection("n", cl::desc( enum ActionType { AC_AsLex, AC_Assemble, - AC_Disassemble + AC_Disassemble, + AC_EDisassemble }; static cl::opt @@ -109,6 +110,8 @@ Action(cl::desc("Action to perform:"), "Assemble a .s file (default)"), clEnumValN(AC_Disassemble, "disassemble", "Disassemble strings of hex bytes"), + clEnumValN(AC_EDisassemble, "edis", + "Enhanced disassembly of strings of hex bytes"), clEnumValEnd)); static const Target *GetTarget(const char *ProgName) { @@ -325,7 +328,7 @@ static int AssembleInput(const char *ProgName) { return Res; } -static int DisassembleInput(const char *ProgName) { +static int DisassembleInput(const char *ProgName, bool Enhanced) { const Target *TheTarget = GetTarget(ProgName); if (!TheTarget) return 0; @@ -344,7 +347,10 @@ static int DisassembleInput(const char *ProgName) { return 1; } - return Disassembler::disassemble(*TheTarget, TripleName, *Buffer); + if (Enhanced) + return Disassembler::disassembleEnhanced(TripleName, *Buffer); + else + return Disassembler::disassemble(*TheTarget, TripleName, *Buffer); } @@ -371,7 +377,9 @@ int main(int argc, char **argv) { case AC_Assemble: return AssembleInput(argv[0]); case AC_Disassemble: - return DisassembleInput(argv[0]); + return DisassembleInput(argv[0], false); + case AC_EDisassemble: + return DisassembleInput(argv[0], true); } return 0;