1//===-- lib/MC/MCExternalSymbolizer.cpp - External symbolizer ---*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "llvm/MC/MCExternalSymbolizer.h"
11#include "llvm/MC/MCContext.h"
12#include "llvm/MC/MCExpr.h"
13#include "llvm/MC/MCInst.h"
14#include "llvm/Support/raw_ostream.h"
15#include <cstring>
16
17using namespace llvm;
18
19// This function tries to add a symbolic operand in place of the immediate
20// Value in the MCInst. The immediate Value has had any PC adjustment made by
21// the caller. If the instruction is a branch instruction then IsBranch is true,
22// else false. If the getOpInfo() function was set as part of the
23// setupForSymbolicDisassembly() call then that function is called to get any
24// symbolic information at the Address for this instruction. If that returns
25// non-zero then the symbolic information it returns is used to create an MCExpr
26// and that is added as an operand to the MCInst. If getOpInfo() returns zero
27// and IsBranch is true then a symbol look up for Value is done and if a symbol
28// is found an MCExpr is created with that, else an MCExpr with Value is
29// created. This function returns true if it adds an operand to the MCInst and
30// false otherwise.
31bool MCExternalSymbolizer::tryAddingSymbolicOperand(MCInst &MI,
32                                                    raw_ostream &cStream,
33                                                    int64_t Value,
34                                                    uint64_t Address,
35                                                    bool IsBranch,
36                                                    uint64_t Offset,
37                                                    uint64_t InstSize) {
38  struct LLVMOpInfo1 SymbolicOp;
39  std::memset(&SymbolicOp, '\0', sizeof(struct LLVMOpInfo1));
40  SymbolicOp.Value = Value;
41
42  if (!GetOpInfo ||
43      !GetOpInfo(DisInfo, Address, Offset, InstSize, 1, &SymbolicOp)) {
44    // Clear SymbolicOp.Value from above and also all other fields.
45    std::memset(&SymbolicOp, '\0', sizeof(struct LLVMOpInfo1));
46    if (!SymbolLookUp)
47      return false;
48    uint64_t ReferenceType;
49    if (IsBranch)
50       ReferenceType = LLVMDisassembler_ReferenceType_In_Branch;
51    else
52       ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
53    const char *ReferenceName;
54    const char *Name = SymbolLookUp(DisInfo, Value, &ReferenceType, Address,
55                                    &ReferenceName);
56    if (Name) {
57      SymbolicOp.AddSymbol.Name = Name;
58      SymbolicOp.AddSymbol.Present = true;
59    }
60    // For branches always create an MCExpr so it gets printed as hex address.
61    else if (IsBranch) {
62      SymbolicOp.Value = Value;
63    }
64    if(ReferenceType == LLVMDisassembler_ReferenceType_Out_SymbolStub)
65      cStream << "symbol stub for: " << ReferenceName;
66    if (!Name && !IsBranch)
67      return false;
68  }
69
70  const MCExpr *Add = NULL;
71  if (SymbolicOp.AddSymbol.Present) {
72    if (SymbolicOp.AddSymbol.Name) {
73      StringRef Name(SymbolicOp.AddSymbol.Name);
74      MCSymbol *Sym = Ctx.GetOrCreateSymbol(Name);
75      Add = MCSymbolRefExpr::Create(Sym, Ctx);
76    } else {
77      Add = MCConstantExpr::Create((int)SymbolicOp.AddSymbol.Value, Ctx);
78    }
79  }
80
81  const MCExpr *Sub = NULL;
82  if (SymbolicOp.SubtractSymbol.Present) {
83      if (SymbolicOp.SubtractSymbol.Name) {
84      StringRef Name(SymbolicOp.SubtractSymbol.Name);
85      MCSymbol *Sym = Ctx.GetOrCreateSymbol(Name);
86      Sub = MCSymbolRefExpr::Create(Sym, Ctx);
87    } else {
88      Sub = MCConstantExpr::Create((int)SymbolicOp.SubtractSymbol.Value, Ctx);
89    }
90  }
91
92  const MCExpr *Off = NULL;
93  if (SymbolicOp.Value != 0)
94    Off = MCConstantExpr::Create(SymbolicOp.Value, Ctx);
95
96  const MCExpr *Expr;
97  if (Sub) {
98    const MCExpr *LHS;
99    if (Add)
100      LHS = MCBinaryExpr::CreateSub(Add, Sub, Ctx);
101    else
102      LHS = MCUnaryExpr::CreateMinus(Sub, Ctx);
103    if (Off != 0)
104      Expr = MCBinaryExpr::CreateAdd(LHS, Off, Ctx);
105    else
106      Expr = LHS;
107  } else if (Add) {
108    if (Off != 0)
109      Expr = MCBinaryExpr::CreateAdd(Add, Off, Ctx);
110    else
111      Expr = Add;
112  } else {
113    if (Off != 0)
114      Expr = Off;
115    else
116      Expr = MCConstantExpr::Create(0, Ctx);
117  }
118
119  Expr = RelInfo->createExprForCAPIVariantKind(Expr, SymbolicOp.VariantKind);
120  if (!Expr)
121    return false;
122
123  MI.addOperand(MCOperand::CreateExpr(Expr));
124  return true;
125}
126
127// This function tries to add a comment as to what is being referenced by a load
128// instruction with the base register that is the Pc.  These can often be values
129// in a literal pool near the Address of the instruction. The Address of the
130// instruction and its immediate Value are used as a possible literal pool entry.
131// The SymbolLookUp call back will return the name of a symbol referenced by the
132// literal pool's entry if the referenced address is that of a symbol. Or it
133// will return a pointer to a literal 'C' string if the referenced address of
134// the literal pool's entry is an address into a section with C string literals.
135void MCExternalSymbolizer::tryAddingPcLoadReferenceComment(raw_ostream &cStream,
136                                                           int64_t Value,
137                                                           uint64_t Address) {
138  if (SymbolLookUp) {
139    uint64_t ReferenceType = LLVMDisassembler_ReferenceType_In_PCrel_Load;
140    const char *ReferenceName;
141    (void)SymbolLookUp(DisInfo, Value, &ReferenceType, Address, &ReferenceName);
142    if(ReferenceType == LLVMDisassembler_ReferenceType_Out_LitPool_SymAddr ||
143       ReferenceType == LLVMDisassembler_ReferenceType_Out_LitPool_CstrAddr)
144      cStream << "literal pool for: " << ReferenceName;
145  }
146}
147
148namespace llvm {
149MCSymbolizer *createMCSymbolizer(StringRef TT, LLVMOpInfoCallback GetOpInfo,
150                                 LLVMSymbolLookupCallback SymbolLookUp,
151                                 void *DisInfo,
152                                 MCContext *Ctx,
153                                 MCRelocationInfo *RelInfo) {
154  assert(Ctx != 0 && "No MCContext given for symbolic disassembly");
155
156  OwningPtr<MCRelocationInfo> RelInfoOwingPtr(RelInfo);
157  return new MCExternalSymbolizer(*Ctx, RelInfoOwingPtr, GetOpInfo,
158                                  SymbolLookUp, DisInfo);
159}
160}
161