1*9880d681SAndroid Build Coastguard Worker //===- AArch64ExternalSymbolizer.cpp - Symbolizer for AArch64 ---*- C++ -*-===//
2*9880d681SAndroid Build Coastguard Worker //
3*9880d681SAndroid Build Coastguard Worker // The LLVM Compiler Infrastructure
4*9880d681SAndroid Build Coastguard Worker //
5*9880d681SAndroid Build Coastguard Worker // This file is distributed under the University of Illinois Open Source
6*9880d681SAndroid Build Coastguard Worker // License. See LICENSE.TXT for details.
7*9880d681SAndroid Build Coastguard Worker //
8*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
9*9880d681SAndroid Build Coastguard Worker
10*9880d681SAndroid Build Coastguard Worker #include "AArch64ExternalSymbolizer.h"
11*9880d681SAndroid Build Coastguard Worker #include "AArch64Subtarget.h"
12*9880d681SAndroid Build Coastguard Worker #include "MCTargetDesc/AArch64AddressingModes.h"
13*9880d681SAndroid Build Coastguard Worker #include "Utils/AArch64BaseInfo.h"
14*9880d681SAndroid Build Coastguard Worker #include "llvm/MC/MCContext.h"
15*9880d681SAndroid Build Coastguard Worker #include "llvm/MC/MCExpr.h"
16*9880d681SAndroid Build Coastguard Worker #include "llvm/MC/MCInst.h"
17*9880d681SAndroid Build Coastguard Worker #include "llvm/Support/Format.h"
18*9880d681SAndroid Build Coastguard Worker #include "llvm/Support/raw_ostream.h"
19*9880d681SAndroid Build Coastguard Worker
20*9880d681SAndroid Build Coastguard Worker using namespace llvm;
21*9880d681SAndroid Build Coastguard Worker
22*9880d681SAndroid Build Coastguard Worker #define DEBUG_TYPE "aarch64-disassembler"
23*9880d681SAndroid Build Coastguard Worker
24*9880d681SAndroid Build Coastguard Worker static MCSymbolRefExpr::VariantKind
getVariant(uint64_t LLVMDisassembler_VariantKind)25*9880d681SAndroid Build Coastguard Worker getVariant(uint64_t LLVMDisassembler_VariantKind) {
26*9880d681SAndroid Build Coastguard Worker switch (LLVMDisassembler_VariantKind) {
27*9880d681SAndroid Build Coastguard Worker case LLVMDisassembler_VariantKind_None:
28*9880d681SAndroid Build Coastguard Worker return MCSymbolRefExpr::VK_None;
29*9880d681SAndroid Build Coastguard Worker case LLVMDisassembler_VariantKind_ARM64_PAGE:
30*9880d681SAndroid Build Coastguard Worker return MCSymbolRefExpr::VK_PAGE;
31*9880d681SAndroid Build Coastguard Worker case LLVMDisassembler_VariantKind_ARM64_PAGEOFF:
32*9880d681SAndroid Build Coastguard Worker return MCSymbolRefExpr::VK_PAGEOFF;
33*9880d681SAndroid Build Coastguard Worker case LLVMDisassembler_VariantKind_ARM64_GOTPAGE:
34*9880d681SAndroid Build Coastguard Worker return MCSymbolRefExpr::VK_GOTPAGE;
35*9880d681SAndroid Build Coastguard Worker case LLVMDisassembler_VariantKind_ARM64_GOTPAGEOFF:
36*9880d681SAndroid Build Coastguard Worker return MCSymbolRefExpr::VK_GOTPAGEOFF;
37*9880d681SAndroid Build Coastguard Worker case LLVMDisassembler_VariantKind_ARM64_TLVP:
38*9880d681SAndroid Build Coastguard Worker case LLVMDisassembler_VariantKind_ARM64_TLVOFF:
39*9880d681SAndroid Build Coastguard Worker default:
40*9880d681SAndroid Build Coastguard Worker llvm_unreachable("bad LLVMDisassembler_VariantKind");
41*9880d681SAndroid Build Coastguard Worker }
42*9880d681SAndroid Build Coastguard Worker }
43*9880d681SAndroid Build Coastguard Worker
44*9880d681SAndroid Build Coastguard Worker /// tryAddingSymbolicOperand - tryAddingSymbolicOperand trys to add a symbolic
45*9880d681SAndroid Build Coastguard Worker /// operand in place of the immediate Value in the MCInst. The immediate
46*9880d681SAndroid Build Coastguard Worker /// Value has not had any PC adjustment made by the caller. If the instruction
47*9880d681SAndroid Build Coastguard Worker /// is a branch that adds the PC to the immediate Value then isBranch is
48*9880d681SAndroid Build Coastguard Worker /// Success, else Fail. If GetOpInfo is non-null, then it is called to get any
49*9880d681SAndroid Build Coastguard Worker /// symbolic information at the Address for this instrution. If that returns
50*9880d681SAndroid Build Coastguard Worker /// non-zero then the symbolic information it returns is used to create an
51*9880d681SAndroid Build Coastguard Worker /// MCExpr and that is added as an operand to the MCInst. If GetOpInfo()
52*9880d681SAndroid Build Coastguard Worker /// returns zero and isBranch is Success then a symbol look up for
53*9880d681SAndroid Build Coastguard Worker /// Address + Value is done and if a symbol is found an MCExpr is created with
54*9880d681SAndroid Build Coastguard Worker /// that, else an MCExpr with Address + Value is created. If GetOpInfo()
55*9880d681SAndroid Build Coastguard Worker /// returns zero and isBranch is Fail then the Opcode of the MCInst is
56*9880d681SAndroid Build Coastguard Worker /// tested and for ADRP an other instructions that help to load of pointers
57*9880d681SAndroid Build Coastguard Worker /// a symbol look up is done to see it is returns a specific reference type
58*9880d681SAndroid Build Coastguard Worker /// to add to the comment stream. This function returns Success if it adds
59*9880d681SAndroid Build Coastguard Worker /// an operand to the MCInst and Fail otherwise.
tryAddingSymbolicOperand(MCInst & MI,raw_ostream & CommentStream,int64_t Value,uint64_t Address,bool IsBranch,uint64_t Offset,uint64_t InstSize)60*9880d681SAndroid Build Coastguard Worker bool AArch64ExternalSymbolizer::tryAddingSymbolicOperand(
61*9880d681SAndroid Build Coastguard Worker MCInst &MI, raw_ostream &CommentStream, int64_t Value, uint64_t Address,
62*9880d681SAndroid Build Coastguard Worker bool IsBranch, uint64_t Offset, uint64_t InstSize) {
63*9880d681SAndroid Build Coastguard Worker // FIXME: This method shares a lot of code with
64*9880d681SAndroid Build Coastguard Worker // MCExternalSymbolizer::tryAddingSymbolicOperand. It may be possible
65*9880d681SAndroid Build Coastguard Worker // refactor the MCExternalSymbolizer interface to allow more of this
66*9880d681SAndroid Build Coastguard Worker // implementation to be shared.
67*9880d681SAndroid Build Coastguard Worker //
68*9880d681SAndroid Build Coastguard Worker struct LLVMOpInfo1 SymbolicOp;
69*9880d681SAndroid Build Coastguard Worker memset(&SymbolicOp, '\0', sizeof(struct LLVMOpInfo1));
70*9880d681SAndroid Build Coastguard Worker SymbolicOp.Value = Value;
71*9880d681SAndroid Build Coastguard Worker uint64_t ReferenceType;
72*9880d681SAndroid Build Coastguard Worker const char *ReferenceName;
73*9880d681SAndroid Build Coastguard Worker if (!GetOpInfo ||
74*9880d681SAndroid Build Coastguard Worker !GetOpInfo(DisInfo, Address, 0 /* Offset */, InstSize, 1, &SymbolicOp)) {
75*9880d681SAndroid Build Coastguard Worker if (IsBranch) {
76*9880d681SAndroid Build Coastguard Worker ReferenceType = LLVMDisassembler_ReferenceType_In_Branch;
77*9880d681SAndroid Build Coastguard Worker const char *Name = SymbolLookUp(DisInfo, Address + Value, &ReferenceType,
78*9880d681SAndroid Build Coastguard Worker Address, &ReferenceName);
79*9880d681SAndroid Build Coastguard Worker if (Name) {
80*9880d681SAndroid Build Coastguard Worker SymbolicOp.AddSymbol.Name = Name;
81*9880d681SAndroid Build Coastguard Worker SymbolicOp.AddSymbol.Present = true;
82*9880d681SAndroid Build Coastguard Worker SymbolicOp.Value = 0;
83*9880d681SAndroid Build Coastguard Worker } else {
84*9880d681SAndroid Build Coastguard Worker SymbolicOp.Value = Address + Value;
85*9880d681SAndroid Build Coastguard Worker }
86*9880d681SAndroid Build Coastguard Worker if (ReferenceType == LLVMDisassembler_ReferenceType_Out_SymbolStub)
87*9880d681SAndroid Build Coastguard Worker CommentStream << "symbol stub for: " << ReferenceName;
88*9880d681SAndroid Build Coastguard Worker else if (ReferenceType ==
89*9880d681SAndroid Build Coastguard Worker LLVMDisassembler_ReferenceType_Out_Objc_Message)
90*9880d681SAndroid Build Coastguard Worker CommentStream << "Objc message: " << ReferenceName;
91*9880d681SAndroid Build Coastguard Worker } else if (MI.getOpcode() == AArch64::ADRP) {
92*9880d681SAndroid Build Coastguard Worker ReferenceType = LLVMDisassembler_ReferenceType_In_ARM64_ADRP;
93*9880d681SAndroid Build Coastguard Worker // otool expects the fully encoded ADRP instruction to be passed in as
94*9880d681SAndroid Build Coastguard Worker // the value here, so reconstruct it:
95*9880d681SAndroid Build Coastguard Worker const MCRegisterInfo &MCRI = *Ctx.getRegisterInfo();
96*9880d681SAndroid Build Coastguard Worker uint32_t EncodedInst = 0x90000000;
97*9880d681SAndroid Build Coastguard Worker EncodedInst |= (Value & 0x3) << 29; // immlo
98*9880d681SAndroid Build Coastguard Worker EncodedInst |= ((Value >> 2) & 0x7FFFF) << 5; // immhi
99*9880d681SAndroid Build Coastguard Worker EncodedInst |= MCRI.getEncodingValue(MI.getOperand(0).getReg()); // reg
100*9880d681SAndroid Build Coastguard Worker SymbolLookUp(DisInfo, EncodedInst, &ReferenceType, Address,
101*9880d681SAndroid Build Coastguard Worker &ReferenceName);
102*9880d681SAndroid Build Coastguard Worker CommentStream << format("0x%llx",
103*9880d681SAndroid Build Coastguard Worker 0xfffffffffffff000LL & (Address + Value));
104*9880d681SAndroid Build Coastguard Worker } else if (MI.getOpcode() == AArch64::ADDXri ||
105*9880d681SAndroid Build Coastguard Worker MI.getOpcode() == AArch64::LDRXui ||
106*9880d681SAndroid Build Coastguard Worker MI.getOpcode() == AArch64::LDRXl ||
107*9880d681SAndroid Build Coastguard Worker MI.getOpcode() == AArch64::ADR) {
108*9880d681SAndroid Build Coastguard Worker if (MI.getOpcode() == AArch64::ADDXri)
109*9880d681SAndroid Build Coastguard Worker ReferenceType = LLVMDisassembler_ReferenceType_In_ARM64_ADDXri;
110*9880d681SAndroid Build Coastguard Worker else if (MI.getOpcode() == AArch64::LDRXui)
111*9880d681SAndroid Build Coastguard Worker ReferenceType = LLVMDisassembler_ReferenceType_In_ARM64_LDRXui;
112*9880d681SAndroid Build Coastguard Worker if (MI.getOpcode() == AArch64::LDRXl) {
113*9880d681SAndroid Build Coastguard Worker ReferenceType = LLVMDisassembler_ReferenceType_In_ARM64_LDRXl;
114*9880d681SAndroid Build Coastguard Worker SymbolLookUp(DisInfo, Address + Value, &ReferenceType, Address,
115*9880d681SAndroid Build Coastguard Worker &ReferenceName);
116*9880d681SAndroid Build Coastguard Worker } else if (MI.getOpcode() == AArch64::ADR) {
117*9880d681SAndroid Build Coastguard Worker ReferenceType = LLVMDisassembler_ReferenceType_In_ARM64_ADR;
118*9880d681SAndroid Build Coastguard Worker SymbolLookUp(DisInfo, Address + Value, &ReferenceType, Address,
119*9880d681SAndroid Build Coastguard Worker &ReferenceName);
120*9880d681SAndroid Build Coastguard Worker } else {
121*9880d681SAndroid Build Coastguard Worker const MCRegisterInfo &MCRI = *Ctx.getRegisterInfo();
122*9880d681SAndroid Build Coastguard Worker // otool expects the fully encoded ADD/LDR instruction to be passed in
123*9880d681SAndroid Build Coastguard Worker // as the value here, so reconstruct it:
124*9880d681SAndroid Build Coastguard Worker unsigned EncodedInst =
125*9880d681SAndroid Build Coastguard Worker MI.getOpcode() == AArch64::ADDXri ? 0x91000000: 0xF9400000;
126*9880d681SAndroid Build Coastguard Worker EncodedInst |= Value << 10; // imm12 [+ shift:2 for ADD]
127*9880d681SAndroid Build Coastguard Worker EncodedInst |=
128*9880d681SAndroid Build Coastguard Worker MCRI.getEncodingValue(MI.getOperand(1).getReg()) << 5; // Rn
129*9880d681SAndroid Build Coastguard Worker EncodedInst |= MCRI.getEncodingValue(MI.getOperand(0).getReg()); // Rd
130*9880d681SAndroid Build Coastguard Worker
131*9880d681SAndroid Build Coastguard Worker SymbolLookUp(DisInfo, EncodedInst, &ReferenceType, Address,
132*9880d681SAndroid Build Coastguard Worker &ReferenceName);
133*9880d681SAndroid Build Coastguard Worker }
134*9880d681SAndroid Build Coastguard Worker if (ReferenceType == LLVMDisassembler_ReferenceType_Out_LitPool_SymAddr)
135*9880d681SAndroid Build Coastguard Worker CommentStream << "literal pool symbol address: " << ReferenceName;
136*9880d681SAndroid Build Coastguard Worker else if (ReferenceType ==
137*9880d681SAndroid Build Coastguard Worker LLVMDisassembler_ReferenceType_Out_LitPool_CstrAddr) {
138*9880d681SAndroid Build Coastguard Worker CommentStream << "literal pool for: \"";
139*9880d681SAndroid Build Coastguard Worker CommentStream.write_escaped(ReferenceName);
140*9880d681SAndroid Build Coastguard Worker CommentStream << "\"";
141*9880d681SAndroid Build Coastguard Worker } else if (ReferenceType ==
142*9880d681SAndroid Build Coastguard Worker LLVMDisassembler_ReferenceType_Out_Objc_CFString_Ref)
143*9880d681SAndroid Build Coastguard Worker CommentStream << "Objc cfstring ref: @\"" << ReferenceName << "\"";
144*9880d681SAndroid Build Coastguard Worker else if (ReferenceType ==
145*9880d681SAndroid Build Coastguard Worker LLVMDisassembler_ReferenceType_Out_Objc_Message)
146*9880d681SAndroid Build Coastguard Worker CommentStream << "Objc message: " << ReferenceName;
147*9880d681SAndroid Build Coastguard Worker else if (ReferenceType ==
148*9880d681SAndroid Build Coastguard Worker LLVMDisassembler_ReferenceType_Out_Objc_Message_Ref)
149*9880d681SAndroid Build Coastguard Worker CommentStream << "Objc message ref: " << ReferenceName;
150*9880d681SAndroid Build Coastguard Worker else if (ReferenceType ==
151*9880d681SAndroid Build Coastguard Worker LLVMDisassembler_ReferenceType_Out_Objc_Selector_Ref)
152*9880d681SAndroid Build Coastguard Worker CommentStream << "Objc selector ref: " << ReferenceName;
153*9880d681SAndroid Build Coastguard Worker else if (ReferenceType ==
154*9880d681SAndroid Build Coastguard Worker LLVMDisassembler_ReferenceType_Out_Objc_Class_Ref)
155*9880d681SAndroid Build Coastguard Worker CommentStream << "Objc class ref: " << ReferenceName;
156*9880d681SAndroid Build Coastguard Worker // For these instructions, the SymbolLookUp() above is just to get the
157*9880d681SAndroid Build Coastguard Worker // ReferenceType and ReferenceName. We want to make sure not to
158*9880d681SAndroid Build Coastguard Worker // fall through so we don't build an MCExpr to leave the disassembly
159*9880d681SAndroid Build Coastguard Worker // of the immediate values of these instructions to the InstPrinter.
160*9880d681SAndroid Build Coastguard Worker return false;
161*9880d681SAndroid Build Coastguard Worker } else {
162*9880d681SAndroid Build Coastguard Worker return false;
163*9880d681SAndroid Build Coastguard Worker }
164*9880d681SAndroid Build Coastguard Worker }
165*9880d681SAndroid Build Coastguard Worker
166*9880d681SAndroid Build Coastguard Worker const MCExpr *Add = nullptr;
167*9880d681SAndroid Build Coastguard Worker if (SymbolicOp.AddSymbol.Present) {
168*9880d681SAndroid Build Coastguard Worker if (SymbolicOp.AddSymbol.Name) {
169*9880d681SAndroid Build Coastguard Worker StringRef Name(SymbolicOp.AddSymbol.Name);
170*9880d681SAndroid Build Coastguard Worker MCSymbol *Sym = Ctx.getOrCreateSymbol(Name);
171*9880d681SAndroid Build Coastguard Worker MCSymbolRefExpr::VariantKind Variant = getVariant(SymbolicOp.VariantKind);
172*9880d681SAndroid Build Coastguard Worker if (Variant != MCSymbolRefExpr::VK_None)
173*9880d681SAndroid Build Coastguard Worker Add = MCSymbolRefExpr::create(Sym, Variant, Ctx);
174*9880d681SAndroid Build Coastguard Worker else
175*9880d681SAndroid Build Coastguard Worker Add = MCSymbolRefExpr::create(Sym, Ctx);
176*9880d681SAndroid Build Coastguard Worker } else {
177*9880d681SAndroid Build Coastguard Worker Add = MCConstantExpr::create(SymbolicOp.AddSymbol.Value, Ctx);
178*9880d681SAndroid Build Coastguard Worker }
179*9880d681SAndroid Build Coastguard Worker }
180*9880d681SAndroid Build Coastguard Worker
181*9880d681SAndroid Build Coastguard Worker const MCExpr *Sub = nullptr;
182*9880d681SAndroid Build Coastguard Worker if (SymbolicOp.SubtractSymbol.Present) {
183*9880d681SAndroid Build Coastguard Worker if (SymbolicOp.SubtractSymbol.Name) {
184*9880d681SAndroid Build Coastguard Worker StringRef Name(SymbolicOp.SubtractSymbol.Name);
185*9880d681SAndroid Build Coastguard Worker MCSymbol *Sym = Ctx.getOrCreateSymbol(Name);
186*9880d681SAndroid Build Coastguard Worker Sub = MCSymbolRefExpr::create(Sym, Ctx);
187*9880d681SAndroid Build Coastguard Worker } else {
188*9880d681SAndroid Build Coastguard Worker Sub = MCConstantExpr::create(SymbolicOp.SubtractSymbol.Value, Ctx);
189*9880d681SAndroid Build Coastguard Worker }
190*9880d681SAndroid Build Coastguard Worker }
191*9880d681SAndroid Build Coastguard Worker
192*9880d681SAndroid Build Coastguard Worker const MCExpr *Off = nullptr;
193*9880d681SAndroid Build Coastguard Worker if (SymbolicOp.Value != 0)
194*9880d681SAndroid Build Coastguard Worker Off = MCConstantExpr::create(SymbolicOp.Value, Ctx);
195*9880d681SAndroid Build Coastguard Worker
196*9880d681SAndroid Build Coastguard Worker const MCExpr *Expr;
197*9880d681SAndroid Build Coastguard Worker if (Sub) {
198*9880d681SAndroid Build Coastguard Worker const MCExpr *LHS;
199*9880d681SAndroid Build Coastguard Worker if (Add)
200*9880d681SAndroid Build Coastguard Worker LHS = MCBinaryExpr::createSub(Add, Sub, Ctx);
201*9880d681SAndroid Build Coastguard Worker else
202*9880d681SAndroid Build Coastguard Worker LHS = MCUnaryExpr::createMinus(Sub, Ctx);
203*9880d681SAndroid Build Coastguard Worker if (Off)
204*9880d681SAndroid Build Coastguard Worker Expr = MCBinaryExpr::createAdd(LHS, Off, Ctx);
205*9880d681SAndroid Build Coastguard Worker else
206*9880d681SAndroid Build Coastguard Worker Expr = LHS;
207*9880d681SAndroid Build Coastguard Worker } else if (Add) {
208*9880d681SAndroid Build Coastguard Worker if (Off)
209*9880d681SAndroid Build Coastguard Worker Expr = MCBinaryExpr::createAdd(Add, Off, Ctx);
210*9880d681SAndroid Build Coastguard Worker else
211*9880d681SAndroid Build Coastguard Worker Expr = Add;
212*9880d681SAndroid Build Coastguard Worker } else {
213*9880d681SAndroid Build Coastguard Worker if (Off)
214*9880d681SAndroid Build Coastguard Worker Expr = Off;
215*9880d681SAndroid Build Coastguard Worker else
216*9880d681SAndroid Build Coastguard Worker Expr = MCConstantExpr::create(0, Ctx);
217*9880d681SAndroid Build Coastguard Worker }
218*9880d681SAndroid Build Coastguard Worker
219*9880d681SAndroid Build Coastguard Worker MI.addOperand(MCOperand::createExpr(Expr));
220*9880d681SAndroid Build Coastguard Worker
221*9880d681SAndroid Build Coastguard Worker return true;
222*9880d681SAndroid Build Coastguard Worker }
223