Adding support for printing operands symbolically to llvm's public 'C'

disassembler API.  Hooked this up to the ARM target so such tools as Darwin's
otool(1) can now print things like branch targets for example this:
  blx _puts
instead of this:
  blx #-36
And even print the expression encoded in the Mach-O relocation entried for
things like this:
  movt r0, :upper16:((_foo-_bar)+1234)


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@129284 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Kevin Enderby
2011-04-11 18:08:50 +00:00
parent 0fb215a154
commit bd3327654b
8 changed files with 212 additions and 9 deletions

View File

@ -17,6 +17,7 @@
#include "ARMDisassemblerCore.h"
#include "ARMAddressingModes.h"
#include "ARMMCExpr.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
@ -1066,7 +1067,8 @@ static bool DisassembleDPFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
// We have an imm16 = imm4:imm12 (imm4=Inst{19:16}, imm12 = Inst{11:0}).
assert(getIBit(insn) == 1 && "I_Bit != '1' reg/imm form");
unsigned Imm16 = slice(insn, 19, 16) << 12 | slice(insn, 11, 0);
MI.addOperand(MCOperand::CreateImm(Imm16));
if (!B->tryAddingSymbolicOperand(Imm16, 4, MI))
MI.addOperand(MCOperand::CreateImm(Imm16));
++OpIdx;
} else {
// We have a reg/imm form.
@ -3628,3 +3630,80 @@ ARMBasicMCBuilder *llvm::CreateMCBuilder(unsigned Opcode, ARMFormat Format) {
return new ARMBasicMCBuilder(Opcode, Format,
ARMInsts[Opcode].getNumOperands());
}
/// tryAddingSymbolicOperand - tryAddingSymbolicOperand trys to add a symbolic
/// operand in place of the immediate Value in the MCInst. The immediate
/// Value has had any PC adjustment made by the caller. If the getOpInfo()
/// function was set as part of the setupBuilderForSymbolicDisassembly() call
/// then that function is called to get any symbolic information at the
/// builder's Address for this instrution. If that returns non-zero then the
/// symbolic information is returns is used to create an MCExpr and that is
/// added as an operand to the MCInst. This function returns true if it adds
/// an operand to the MCInst and false otherwise.
bool ARMBasicMCBuilder::tryAddingSymbolicOperand(uint64_t Value,
uint64_t InstSize,
MCInst &MI) {
if (!GetOpInfo)
return false;
struct LLVMOpInfo1 SymbolicOp;
SymbolicOp.Value = Value;
if (!GetOpInfo(DisInfo, Address, 0 /* Offset */, InstSize, 1, &SymbolicOp))
return false;
const MCExpr *Add = NULL;
if (SymbolicOp.AddSymbol.Present) {
if (SymbolicOp.AddSymbol.Name) {
StringRef Name(SymbolicOp.AddSymbol.Name);
MCSymbol *Sym = Ctx->GetOrCreateSymbol(Name);
Add = MCSymbolRefExpr::Create(Sym, *Ctx);
} else {
Add = MCConstantExpr::Create(SymbolicOp.AddSymbol.Value, *Ctx);
}
}
const MCExpr *Sub = NULL;
if (SymbolicOp.SubtractSymbol.Present) {
if (SymbolicOp.SubtractSymbol.Name) {
StringRef Name(SymbolicOp.SubtractSymbol.Name);
MCSymbol *Sym = Ctx->GetOrCreateSymbol(Name);
Sub = MCSymbolRefExpr::Create(Sym, *Ctx);
} else {
Sub = MCConstantExpr::Create(SymbolicOp.SubtractSymbol.Value, *Ctx);
}
}
const MCExpr *Off = NULL;
if (SymbolicOp.Value != 0)
Off = MCConstantExpr::Create(SymbolicOp.Value, *Ctx);
const MCExpr *Expr;
if (Sub) {
const MCExpr *LHS;
if (Add)
LHS = MCBinaryExpr::CreateSub(Add, Sub, *Ctx);
else
LHS = MCUnaryExpr::CreateMinus(Sub, *Ctx);
if (Off != 0)
Expr = MCBinaryExpr::CreateAdd(LHS, Off, *Ctx);
else
Expr = LHS;
} else if (Add) {
if (Off != 0)
Expr = MCBinaryExpr::CreateAdd(Add, Off, *Ctx);
else
Expr = Add;
} else
Expr = Off;
if (SymbolicOp.VariantKind == LLVMDisassembler_VariantKind_ARM_HI16)
MI.addOperand(MCOperand::CreateExpr(ARMMCExpr::CreateUpper16(Expr, *Ctx)));
else if (SymbolicOp.VariantKind == LLVMDisassembler_VariantKind_ARM_LO16)
MI.addOperand(MCOperand::CreateExpr(ARMMCExpr::CreateLower16(Expr, *Ctx)));
else if (SymbolicOp.VariantKind == LLVMDisassembler_VariantKind_None)
MI.addOperand(MCOperand::CreateExpr(Expr));
else
assert("bad SymbolicOp.VariantKind");
return true;
}