xref: /freebsd/contrib/llvm-project/llvm/lib/MC/MCDisassembler/MCExternalSymbolizer.cpp (revision ec0ea6efa1ad229d75c394c1a9b9cac33af2b1d3)
1 //===-- MCExternalSymbolizer.cpp - External symbolizer --------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "llvm/MC/MCDisassembler/MCExternalSymbolizer.h"
10 #include "llvm/MC/MCContext.h"
11 #include "llvm/MC/MCExpr.h"
12 #include "llvm/MC/MCInst.h"
13 #include "llvm/Support/raw_ostream.h"
14 #include <cstring>
15 
16 using namespace llvm;
17 
18 namespace llvm {
19 class Triple;
20 }
21 
22 // This function tries to add a symbolic operand in place of the immediate
23 // Value in the MCInst. The immediate Value has had any PC adjustment made by
24 // the caller. If the instruction is a branch instruction then IsBranch is true,
25 // else false. If the getOpInfo() function was set as part of the
26 // setupForSymbolicDisassembly() call then that function is called to get any
27 // symbolic information at the Address for this instruction. If that returns
28 // non-zero then the symbolic information it returns is used to create an MCExpr
29 // and that is added as an operand to the MCInst. If getOpInfo() returns zero
30 // and IsBranch is true then a symbol look up for Value is done and if a symbol
31 // is found an MCExpr is created with that, else an MCExpr with Value is
32 // created. This function returns true if it adds an operand to the MCInst and
33 // false otherwise.
34 bool MCExternalSymbolizer::tryAddingSymbolicOperand(MCInst &MI,
35                                                     raw_ostream &cStream,
36                                                     int64_t Value,
37                                                     uint64_t Address,
38                                                     bool IsBranch,
39                                                     uint64_t Offset,
40                                                     uint64_t InstSize) {
41   struct LLVMOpInfo1 SymbolicOp;
42   std::memset(&SymbolicOp, '\0', sizeof(struct LLVMOpInfo1));
43   SymbolicOp.Value = Value;
44 
45   if (!GetOpInfo ||
46       !GetOpInfo(DisInfo, Address, Offset, InstSize, 1, &SymbolicOp)) {
47     // Clear SymbolicOp.Value from above and also all other fields.
48     std::memset(&SymbolicOp, '\0', sizeof(struct LLVMOpInfo1));
49 
50     // At this point, GetOpInfo() did not find any relocation information about
51     // this operand and we are left to use the SymbolLookUp() call back to guess
52     // if the Value is the address of a symbol.  In the case this is a branch
53     // that always makes sense to guess.  But in the case of an immediate it is
54     // a bit more questionable if it is an address of a symbol or some other
55     // reference.  So if the immediate Value comes from a width of 1 byte,
56     // InstSize, we will not guess it is an address of a symbol.  Because in
57     // object files assembled starting at address 0 this usually leads to
58     // incorrect symbolication.
59     if (!SymbolLookUp || (InstSize == 1 && !IsBranch))
60       return false;
61 
62     uint64_t ReferenceType;
63     if (IsBranch)
64        ReferenceType = LLVMDisassembler_ReferenceType_In_Branch;
65     else
66        ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
67     const char *ReferenceName;
68     const char *Name = SymbolLookUp(DisInfo, Value, &ReferenceType, Address,
69                                     &ReferenceName);
70     if (Name) {
71       SymbolicOp.AddSymbol.Name = Name;
72       SymbolicOp.AddSymbol.Present = true;
73       // If Name is a C++ symbol name put the human readable name in a comment.
74       if(ReferenceType == LLVMDisassembler_ReferenceType_DeMangled_Name)
75         cStream << ReferenceName;
76     }
77     // For branches always create an MCExpr so it gets printed as hex address.
78     else if (IsBranch) {
79       SymbolicOp.Value = Value;
80     }
81     if(ReferenceType == LLVMDisassembler_ReferenceType_Out_SymbolStub)
82       cStream << "symbol stub for: " << ReferenceName;
83     else if(ReferenceType == LLVMDisassembler_ReferenceType_Out_Objc_Message)
84       cStream << "Objc message: " << ReferenceName;
85     if (!Name && !IsBranch)
86       return false;
87   }
88 
89   const MCExpr *Add = nullptr;
90   if (SymbolicOp.AddSymbol.Present) {
91     if (SymbolicOp.AddSymbol.Name) {
92       StringRef Name(SymbolicOp.AddSymbol.Name);
93       MCSymbol *Sym = Ctx.getOrCreateSymbol(Name);
94       Add = MCSymbolRefExpr::create(Sym, Ctx);
95     } else {
96       Add = MCConstantExpr::create((int)SymbolicOp.AddSymbol.Value, Ctx);
97     }
98   }
99 
100   const MCExpr *Sub = nullptr;
101   if (SymbolicOp.SubtractSymbol.Present) {
102       if (SymbolicOp.SubtractSymbol.Name) {
103       StringRef Name(SymbolicOp.SubtractSymbol.Name);
104       MCSymbol *Sym = Ctx.getOrCreateSymbol(Name);
105       Sub = MCSymbolRefExpr::create(Sym, Ctx);
106     } else {
107       Sub = MCConstantExpr::create((int)SymbolicOp.SubtractSymbol.Value, Ctx);
108     }
109   }
110 
111   const MCExpr *Off = nullptr;
112   if (SymbolicOp.Value != 0)
113     Off = MCConstantExpr::create(SymbolicOp.Value, Ctx);
114 
115   const MCExpr *Expr;
116   if (Sub) {
117     const MCExpr *LHS;
118     if (Add)
119       LHS = MCBinaryExpr::createSub(Add, Sub, Ctx);
120     else
121       LHS = MCUnaryExpr::createMinus(Sub, Ctx);
122     if (Off)
123       Expr = MCBinaryExpr::createAdd(LHS, Off, Ctx);
124     else
125       Expr = LHS;
126   } else if (Add) {
127     if (Off)
128       Expr = MCBinaryExpr::createAdd(Add, Off, Ctx);
129     else
130       Expr = Add;
131   } else {
132     if (Off)
133       Expr = Off;
134     else
135       Expr = MCConstantExpr::create(0, Ctx);
136   }
137 
138   Expr = RelInfo->createExprForCAPIVariantKind(Expr, SymbolicOp.VariantKind);
139   if (!Expr)
140     return false;
141 
142   MI.addOperand(MCOperand::createExpr(Expr));
143   return true;
144 }
145 
146 // This function tries to add a comment as to what is being referenced by a load
147 // instruction with the base register that is the Pc.  These can often be values
148 // in a literal pool near the Address of the instruction. The Address of the
149 // instruction and its immediate Value are used as a possible literal pool entry.
150 // The SymbolLookUp call back will return the name of a symbol referenced by the
151 // literal pool's entry if the referenced address is that of a symbol. Or it
152 // will return a pointer to a literal 'C' string if the referenced address of
153 // the literal pool's entry is an address into a section with C string literals.
154 // Or if the reference is to an Objective-C data structure it will return a
155 // specific reference type for it and a string.
156 void MCExternalSymbolizer::tryAddingPcLoadReferenceComment(raw_ostream &cStream,
157                                                            int64_t Value,
158                                                            uint64_t Address) {
159   if (SymbolLookUp) {
160     uint64_t ReferenceType = LLVMDisassembler_ReferenceType_In_PCrel_Load;
161     const char *ReferenceName;
162     (void)SymbolLookUp(DisInfo, Value, &ReferenceType, Address, &ReferenceName);
163     if(ReferenceType == LLVMDisassembler_ReferenceType_Out_LitPool_SymAddr)
164       cStream << "literal pool symbol address: " << ReferenceName;
165     else if(ReferenceType ==
166             LLVMDisassembler_ReferenceType_Out_LitPool_CstrAddr) {
167       cStream << "literal pool for: \"";
168       cStream.write_escaped(ReferenceName);
169       cStream << "\"";
170     }
171     else if(ReferenceType ==
172             LLVMDisassembler_ReferenceType_Out_Objc_CFString_Ref)
173       cStream << "Objc cfstring ref: @\"" << ReferenceName << "\"";
174     else if(ReferenceType ==
175             LLVMDisassembler_ReferenceType_Out_Objc_Message)
176       cStream << "Objc message: " << ReferenceName;
177     else if(ReferenceType ==
178             LLVMDisassembler_ReferenceType_Out_Objc_Message_Ref)
179       cStream << "Objc message ref: " << ReferenceName;
180     else if(ReferenceType ==
181             LLVMDisassembler_ReferenceType_Out_Objc_Selector_Ref)
182       cStream << "Objc selector ref: " << ReferenceName;
183     else if(ReferenceType ==
184             LLVMDisassembler_ReferenceType_Out_Objc_Class_Ref)
185       cStream << "Objc class ref: " << ReferenceName;
186   }
187 }
188 
189 namespace llvm {
190 MCSymbolizer *createMCSymbolizer(const Triple &TT, LLVMOpInfoCallback GetOpInfo,
191                                  LLVMSymbolLookupCallback SymbolLookUp,
192                                  void *DisInfo, MCContext *Ctx,
193                                  std::unique_ptr<MCRelocationInfo> &&RelInfo) {
194   assert(Ctx && "No MCContext given for symbolic disassembly");
195 
196   return new MCExternalSymbolizer(*Ctx, std::move(RelInfo), GetOpInfo,
197                                   SymbolLookUp, DisInfo);
198 }
199 }
200