Index: include/llvm-c/Disassembler.h =================================================================== --- include/llvm-c/Disassembler.h +++ include/llvm-c/Disassembler.h @@ -18,6 +18,8 @@ #include "llvm/Support/DataTypes.h" #include +#include "llvm-c/MCInst.h" + /** * @defgroup LLVMCDisassembler Disassembler * @ingroup LLVMC @@ -221,13 +223,22 @@ * parameter Bytes, and contains at least BytesSize number of bytes. The * instruction is at the address specified by the PC parameter. If a valid * instruction can be disassembled, its string is returned indirectly in - * OutString whose size is specified in the parameter OutStringSize. This - * function returns the number of bytes in the instruction or zero if there was - * no valid instruction. + * OutString whose size is specified in the parameter OutStringSize. + * If a MCInstRef is provided, the MCInst generated during disassembly is + * written there. This function returns the number of bytes in the instruction + * or zero if there was no valid instruction. + */ +size_t LLVMDisasmMCInst(LLVMDisasmContextRef DC, uint8_t *Bytes, + uint64_t BytesSize, uint64_t PC, + LLVMMCInstRef* Inst, + char *OutString, size_t OutStringSize); + +/** + * As LLVMDisasmMCInst, but never return an MCInst. */ size_t LLVMDisasmInstruction(LLVMDisasmContextRef DC, uint8_t *Bytes, uint64_t BytesSize, uint64_t PC, - char *OutString, size_t OutStringSize); + char* OutString, size_t OutStringSize); /** * @} Index: include/llvm-c/MCInst.h =================================================================== --- /dev/null +++ include/llvm-c/MCInst.h @@ -0,0 +1,107 @@ +/*===-- llvm-c/MCInst.h - Disassembler Public C Interface ---*- C -*-===*\ +|* *| +|* The LLVM Compiler Infrastructure *| +|* *| +|* This file is distributed under the University of Illinois Open Source *| +|* License. See LICENSE.TXT for details. *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header provides a public interface the MCInst type. *| +|* LLVM provides an implementation of this interface. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_C_MCINST_H +#define LLVM_C_MCINST_H + +#include "llvm/Support/DataTypes.h" +#include + +/** + * @defgroup LLVMCInst MCInst + * @ingroup LLVMC + * + * @{ + */ + +/** + * An opaque reference to a native instruction. + */ +typedef void *LLVMMCInstRef; + +/** + * Opaque type for MCOperand. + */ +typedef void* LLVMMCOperandRef; + +/** + * Type tag for different kinds of operands. + */ +typedef enum { + LLVMOKInvalid, + LLVMOKReg, + LLVMOKImm, + LLVMOKFPImm, + LLVMOKExpr, + LLVMOKInst +} LLVMMCOperandKind; + +#ifdef __cplusplus +extern "C" { +#endif /* !defined(__cplusplus) */ + +/** + * Dispose of an instruction. + */ +void LLVMMCInstRefDispose(LLVMMCInstRef Inst); + +/** + * Get total number of operands for an instruction. + */ +unsigned LLVMMCInstGetNumOperands(LLVMMCInstRef Inst); + +/** + * Get the operand kind of the ith operand. + */ +LLVMMCOperandKind LLVMMCInstGetOperandKind(LLVMMCInstRef Inst, unsigned i); + +/** + * Return the register value of the ith operand. Should only be called if + * the OperandKind is LLVMOKReg. + */ +unsigned LLVMMCInstGetOperandRegVal(LLVMMCInstRef Inst, unsigned i); + +/** + * Return the immediate value of the ith operand. Should only be called if + * the OperandKind is LLVMOKImm. + */ +int64_t LLVMMCInstGetOperandImmVal(LLVMMCInstRef Inst, unsigned i); + +/** + * Return the immediate floating point value of the ith operand. Should only + * be called if the OperandKind is LLVMOKFPImm. + */ +double LLVMMCInstGetOperandFPImmVal(LLVMMCInstRef Inst, unsigned i); + +/** + * Return the instruction value of the ith operand. Should only be called if + * the OperandKind is LLVMOKInst. + */ +LLVMMCInstRef LLVMMCInstGetOperandMCInst(LLVMMCInstRef Inst, unsigned i); + +/** + * Get the opcode of a particular MCInst. + * Reference tblgen files for actual values. + */ +unsigned LLVMMCInstGetOpcode(LLVMMCInstRef Inst); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* !defined(__cplusplus) */ + +#endif /* !defined(LLVM_C_MCINST_H) */ Index: lib/MC/MCDisassembler/Disassembler.cpp =================================================================== --- lib/MC/MCDisassembler/Disassembler.cpp +++ lib/MC/MCDisassembler/Disassembler.cpp @@ -247,7 +247,7 @@ } // -// LLVMDisasmInstruction() disassembles a single instruction using the +// LLVMDisasmMCInst() disassembles a single instruction using the // disassembler context specified in the parameter DC. The bytes of the // instruction are specified in the parameter Bytes, and contains at least // BytesSize number of bytes. The instruction is at the address specified by @@ -258,9 +258,10 @@ // returns zero the caller will have to pick how many bytes they want to step // over by printing a .byte, .long etc. to continue. // -size_t LLVMDisasmInstruction(LLVMDisasmContextRef DCR, uint8_t *Bytes, - uint64_t BytesSize, uint64_t PC, char *OutString, - size_t OutStringSize){ +size_t LLVMDisasmMCInst(LLVMDisasmContextRef DCR, uint8_t *Bytes, + uint64_t BytesSize, uint64_t PC, + LLVMMCInstRef* InstOut, + char *OutString, size_t OutStringSize){ LLVMDisasmContext *DC = (LLVMDisasmContext *)DCR; // Wrap the pointer to the Bytes, BytesSize and PC in a MemoryObject. DisasmMemoryObject MemoryObject(Bytes, BytesSize, PC); @@ -300,12 +301,22 @@ std::memcpy(OutString, InsnStr.data(), OutputSize); OutString[OutputSize] = '\0'; // Terminate string. + if (InstOut) { + *(MCInst**)InstOut = new MCInst(Inst); + } + return Size; } } llvm_unreachable("Invalid DecodeStatus!"); } +size_t LLVMDisasmInstruction(LLVMDisasmContextRef DCR, uint8_t *Bytes, + uint64_t BytesSize, uint64_t PC, + char *OutString, size_t OutStringSize){ + return LLVMDisasmMCInst(DCR, Bytes, BytesSize, PC, NULL, OutString, OutStringSize); +} + // // LLVMSetDisasmOptions() sets the disassembler's options. It returns 1 if it // can set all the Options and 0 otherwise. Index: lib/MC/MCInst.cpp =================================================================== --- lib/MC/MCInst.cpp +++ lib/MC/MCInst.cpp @@ -13,6 +13,8 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" +#include "llvm-c/MCInst.h" + using namespace llvm; void MCOperand::print(raw_ostream &OS, const MCAsmInfo *MAI) const { @@ -70,3 +72,58 @@ dbgs() << "\n"; } #endif + +void LLVMMCInstRefDispose(LLVMMCInstRef InstR) { + MCInst* Inst = (MCInst*)InstR; + delete Inst; +} + +unsigned LLVMMCInstGetNumOperands(LLVMMCInstRef InstR) { + MCInst* Inst = (MCInst*)InstR; + return Inst->getNumOperands(); +} + +LLVMMCOperandKind LLVMMCInstGetOperandKind(LLVMMCInstRef InstR, unsigned int i) { + MCInst* Inst = (MCInst*)InstR; + MCOperand Operand = Inst->getOperand(i); + if (Operand.isReg()) { + return LLVMOKReg; + } else if (Operand.isImm()) { + return LLVMOKImm; + } else if (Operand.isFPImm()) { + return LLVMOKFPImm; + } else if (Operand.isExpr()) { + return LLVMOKExpr; + } else if (Operand.isInst()) { + return LLVMOKInst; + } else { + assert((!Operand.isValid()) && "Unknown Operand Type"); + return LLVMOKInvalid; + } + return LLVMOKInvalid; +} + +unsigned LLVMMCInstGetOperandRegVal(LLVMMCInstRef InstR, unsigned i) { + MCInst* Inst = (MCInst*)InstR; + return Inst->getOperand(i).getReg(); +} + +int64_t LLVMMCInstGetOperandImmVal(LLVMMCInstRef InstR, unsigned i) { + MCInst* Inst = (MCInst*)InstR; + return Inst->getOperand(i).getImm(); +} + +double LLVMMCInstGetOperandFPImmVal(LLVMMCInstRef InstR, unsigned i) { + MCInst* Inst = (MCInst*)InstR; + return Inst->getOperand(i).getFPImm(); +} + +LLVMMCInstRef LLVMMCInstGetOperandInstVal(LLVMMCInstRef InstR, unsigned i) { + MCInst* Inst = (MCInst*)InstR; + return (LLVMMCInstRef)Inst->getOperand(i).getInst(); +} + +unsigned LLVMMCInstGetOpcode(LLVMMCInstRef InstR) { + MCInst* Inst = (MCInst*)InstR; + return Inst->getOpcode(); +} Index: test/Bindings/llvm-c/disassemble.test =================================================================== --- test/Bindings/llvm-c/disassemble.test +++ test/Bindings/llvm-c/disassemble.test @@ -4,13 +4,17 @@ arm-linux-android 44 26 1f e5 0c 10 4b e2 02 20 81 e0 ;CHECK: triple: arm-linux-android ;CHECK: ldr r2, [pc, #-1604] +;CHECK: 00000000fffff9bc 000000000000000e ;CHECK: sub r1, r11, #12 +;CHECK: 000000000000000c 000000000000000e ;CHECK: 02 20 81 e0 ;CHECK: add r2, r1, r2 +;CHECK: 000000000000000e x86_64-linux-unknown 48 83 c4 38 5b 5d 41 5c 41 5d 41 5e 41 5f c3 ;CHECK: triple: x86_64-linux-unknown ;CHECK: addq $56, %rsp +;CHECK: 0000000000000038 ;CHECK: popq %rbx ;CHECK: popq %rbp ;CHECK: popq %r12 @@ -21,9 +25,12 @@ i686-apple-darwin 0f b7 4c 24 0a e8 29 ce ff ff ;CHECK: movzwl 10(%esp), %ecx +;CHECK: 0000000000000001 000000000000000a ;CHECK: calll -12759 +;CHECK: ffffffffffffce29 i686-linux-unknown dd 44 24 04 d9 e1 c3 ;CHECK: fldl 4(%esp) +;CHECK: 0000000000000001 0000000000000004 ;CHECK: fabs ;CHECK: ret Index: tools/llvm-c-test/CMakeLists.txt =================================================================== --- tools/llvm-c-test/CMakeLists.txt +++ tools/llvm-c-test/CMakeLists.txt @@ -3,6 +3,7 @@ BitReader Core MCDisassembler + MC Object Target ) Index: tools/llvm-c-test/disassemble.c =================================================================== --- tools/llvm-c-test/disassemble.c +++ tools/llvm-c-test/disassemble.c @@ -33,6 +33,22 @@ printf(" %s\n", disasm); } +static void mc_pprint(LLVMMCInstRef Inst) { + /* + * Opcodes and register codes are potentially unstable, across versions, so + * without using tblgen, we just print immediates. + * Floating point numbers can be a little off depending on FPU, so we only + * print integer immediates. + */ + unsigned numOperands = LLVMMCInstGetNumOperands(Inst); + for (unsigned operand = 0; operand < numOperands; operand++) { + if (LLVMMCInstGetOperandKind(Inst, operand) == LLVMOKImm) { + printf("%016lx ", LLVMMCInstGetOperandImmVal(Inst, operand)); + } + } + printf("\n"); +} + static void do_disassemble(const char *triple, unsigned char *buf, int siz) { LLVMDisasmContextRef D = LLVMCreateDisasm(triple, NULL, 0, NULL, NULL); char outline[1024]; @@ -45,13 +61,16 @@ pos = 0; while (pos < siz) { - size_t l = LLVMDisasmInstruction(D, buf + pos, siz - pos, 0, outline, - sizeof(outline)); + LLVMMCInstRef Inst; + size_t l = LLVMDisasmMCInst(D, buf + pos, siz - pos, 0, &Inst, + outline, sizeof(outline)); if (!l) { pprint(pos, buf + pos, 1, "\t???"); pos++; } else { pprint(pos, buf + pos, l, outline); + mc_pprint(Inst); + LLVMMCInstRefDispose(Inst); pos += l; } }