1 //===-- lib/MC/MCObjectSymbolizer.cpp -------------------------------------===// 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/MCObjectSymbolizer.h" 11 #include "llvm/ADT/SmallString.h" 12 #include "llvm/MC/MCContext.h" 13 #include "llvm/MC/MCExpr.h" 14 #include "llvm/MC/MCInst.h" 15 #include "llvm/MC/MCRelocationInfo.h" 16 #include "llvm/MC/MCSymbol.h" 17 #include "llvm/Object/ELFObjectFile.h" 18 #include "llvm/Object/MachO.h" 19 #include "llvm/Support/raw_ostream.h" 20 #include <algorithm> 21 22 using namespace llvm; 23 using namespace object; 24 25 //===- MCMachObjectSymbolizer ---------------------------------------------===// 26 27 namespace { 28 class MCMachObjectSymbolizer : public MCObjectSymbolizer { 29 const MachOObjectFile *MOOF; 30 // __TEXT;__stubs support. 31 uint64_t StubsStart; 32 uint64_t StubsCount; 33 uint64_t StubSize; 34 uint64_t StubsIndSymIndex; 35 36 public: 37 MCMachObjectSymbolizer(MCContext &Ctx, 38 std::unique_ptr<MCRelocationInfo> RelInfo, 39 const MachOObjectFile *MOOF); 40 41 StringRef findExternalFunctionAt(uint64_t Addr) override; 42 43 void tryAddingPcLoadReferenceComment(raw_ostream &cStream, int64_t Value, 44 uint64_t Address) override; 45 }; 46 } // End unnamed namespace 47 48 MCMachObjectSymbolizer::MCMachObjectSymbolizer( 49 MCContext &Ctx, std::unique_ptr<MCRelocationInfo> RelInfo, 50 const MachOObjectFile *MOOF) 51 : MCObjectSymbolizer(Ctx, std::move(RelInfo), MOOF), MOOF(MOOF), 52 StubsStart(0), StubsCount(0), StubSize(0), StubsIndSymIndex(0) { 53 54 for (const SectionRef &Section : MOOF->sections()) { 55 StringRef Name; 56 Section.getName(Name); 57 if (Name == "__stubs") { 58 SectionRef StubsSec = Section; 59 if (MOOF->is64Bit()) { 60 MachO::section_64 S = MOOF->getSection64(StubsSec.getRawDataRefImpl()); 61 StubsIndSymIndex = S.reserved1; 62 StubSize = S.reserved2; 63 } else { 64 MachO::section S = MOOF->getSection(StubsSec.getRawDataRefImpl()); 65 StubsIndSymIndex = S.reserved1; 66 StubSize = S.reserved2; 67 } 68 assert(StubSize && "Mach-O stub entry size can't be zero!"); 69 StubsSec.getAddress(StubsStart); 70 StubsSec.getSize(StubsCount); 71 StubsCount /= StubSize; 72 } 73 } 74 } 75 76 StringRef MCMachObjectSymbolizer::findExternalFunctionAt(uint64_t Addr) { 77 // FIXME: also, this can all be done at the very beginning, by iterating over 78 // all stubs and creating the calls to outside functions. Is it worth it 79 // though? 80 if (!StubSize) 81 return StringRef(); 82 uint64_t StubIdx = (Addr - StubsStart) / StubSize; 83 if (StubIdx >= StubsCount) 84 return StringRef(); 85 86 uint32_t SymtabIdx = 87 MOOF->getIndirectSymbolTableEntry(MOOF->getDysymtabLoadCommand(), StubIdx); 88 89 StringRef SymName; 90 symbol_iterator SI = MOOF->symbol_begin(); 91 for (uint32_t i = 0; i != SymtabIdx; ++i) 92 ++SI; 93 SI->getName(SymName); 94 assert(SI != MOOF->symbol_end() && "Stub wasn't found in the symbol table!"); 95 assert(SymName.front() == '_' && "Mach-O symbol doesn't start with '_'!"); 96 return SymName.substr(1); 97 } 98 99 void MCMachObjectSymbolizer:: 100 tryAddingPcLoadReferenceComment(raw_ostream &cStream, int64_t Value, 101 uint64_t Address) { 102 if (const RelocationRef *R = findRelocationAt(Address)) { 103 const MCExpr *RelExpr = RelInfo->createExprForRelocation(*R); 104 if (!RelExpr || RelExpr->EvaluateAsAbsolute(Value) == false) 105 return; 106 } 107 uint64_t Addr = Value; 108 if (const SectionRef *S = findSectionContaining(Addr)) { 109 StringRef Name; S->getName(Name); 110 uint64_t SAddr; S->getAddress(SAddr); 111 if (Name == "__cstring") { 112 StringRef Contents; 113 S->getContents(Contents); 114 Contents = Contents.substr(Addr - SAddr); 115 cStream << " ## literal pool for: " 116 << Contents.substr(0, Contents.find_first_of(0)); 117 } 118 } 119 } 120 121 //===- MCObjectSymbolizer -------------------------------------------------===// 122 123 MCObjectSymbolizer::MCObjectSymbolizer( 124 MCContext &Ctx, std::unique_ptr<MCRelocationInfo> RelInfo, 125 const ObjectFile *Obj) 126 : MCSymbolizer(Ctx, std::move(RelInfo)), Obj(Obj), SortedSections(), 127 AddrToReloc() {} 128 129 bool MCObjectSymbolizer:: 130 tryAddingSymbolicOperand(MCInst &MI, raw_ostream &cStream, 131 int64_t Value, uint64_t Address, bool IsBranch, 132 uint64_t Offset, uint64_t InstSize) { 133 if (IsBranch) { 134 StringRef ExtFnName = findExternalFunctionAt((uint64_t)Value); 135 if (!ExtFnName.empty()) { 136 MCSymbol *Sym = Ctx.GetOrCreateSymbol(ExtFnName); 137 const MCExpr *Expr = MCSymbolRefExpr::Create(Sym, Ctx); 138 MI.addOperand(MCOperand::CreateExpr(Expr)); 139 return true; 140 } 141 } 142 143 if (const RelocationRef *R = findRelocationAt(Address + Offset)) { 144 if (const MCExpr *RelExpr = RelInfo->createExprForRelocation(*R)) { 145 MI.addOperand(MCOperand::CreateExpr(RelExpr)); 146 return true; 147 } 148 // Only try to create a symbol+offset expression if there is no relocation. 149 return false; 150 } 151 152 // Interpret Value as a branch target. 153 if (IsBranch == false) 154 return false; 155 uint64_t UValue = Value; 156 // FIXME: map instead of looping each time? 157 for (const SymbolRef &Symbol : Obj->symbols()) { 158 uint64_t SymAddr; 159 Symbol.getAddress(SymAddr); 160 uint64_t SymSize; 161 Symbol.getSize(SymSize); 162 StringRef SymName; 163 Symbol.getName(SymName); 164 SymbolRef::Type SymType; 165 Symbol.getType(SymType); 166 if (SymAddr == UnknownAddressOrSize || SymSize == UnknownAddressOrSize || 167 SymName.empty() || SymType != SymbolRef::ST_Function) 168 continue; 169 170 if ( SymAddr == UValue || 171 (SymAddr <= UValue && SymAddr + SymSize > UValue)) { 172 MCSymbol *Sym = Ctx.GetOrCreateSymbol(SymName); 173 const MCExpr *Expr = MCSymbolRefExpr::Create(Sym, Ctx); 174 if (SymAddr != UValue) { 175 const MCExpr *Off = MCConstantExpr::Create(UValue - SymAddr, Ctx); 176 Expr = MCBinaryExpr::CreateAdd(Expr, Off, Ctx); 177 } 178 MI.addOperand(MCOperand::CreateExpr(Expr)); 179 return true; 180 } 181 } 182 return false; 183 } 184 185 void MCObjectSymbolizer:: 186 tryAddingPcLoadReferenceComment(raw_ostream &cStream, 187 int64_t Value, uint64_t Address) { 188 } 189 190 StringRef MCObjectSymbolizer::findExternalFunctionAt(uint64_t Addr) { 191 return StringRef(); 192 } 193 194 MCObjectSymbolizer *MCObjectSymbolizer::createObjectSymbolizer( 195 MCContext &Ctx, std::unique_ptr<MCRelocationInfo> RelInfo, 196 const ObjectFile *Obj) { 197 if (const MachOObjectFile *MOOF = dyn_cast<MachOObjectFile>(Obj)) 198 return new MCMachObjectSymbolizer(Ctx, std::move(RelInfo), MOOF); 199 return new MCObjectSymbolizer(Ctx, std::move(RelInfo), Obj); 200 } 201 202 // SortedSections implementation. 203 204 static bool SectionStartsBefore(const SectionRef &S, uint64_t Addr) { 205 uint64_t SAddr; S.getAddress(SAddr); 206 return SAddr < Addr; 207 } 208 209 const SectionRef *MCObjectSymbolizer::findSectionContaining(uint64_t Addr) { 210 if (SortedSections.empty()) 211 buildSectionList(); 212 213 SortedSectionList::iterator 214 EndIt = SortedSections.end(), 215 It = std::lower_bound(SortedSections.begin(), EndIt, 216 Addr, SectionStartsBefore); 217 if (It == EndIt) 218 return nullptr; 219 uint64_t SAddr; It->getAddress(SAddr); 220 uint64_t SSize; It->getSize(SSize); 221 if (Addr >= SAddr + SSize) 222 return nullptr; 223 return &*It; 224 } 225 226 const RelocationRef *MCObjectSymbolizer::findRelocationAt(uint64_t Addr) { 227 if (AddrToReloc.empty()) 228 buildRelocationByAddrMap(); 229 230 AddrToRelocMap::const_iterator RI = AddrToReloc.find(Addr); 231 if (RI == AddrToReloc.end()) 232 return nullptr; 233 return &RI->second; 234 } 235 236 void MCObjectSymbolizer::buildSectionList() { 237 for (const SectionRef &Section : Obj->sections()) { 238 bool RequiredForExec; 239 Section.isRequiredForExecution(RequiredForExec); 240 if (RequiredForExec == false) 241 continue; 242 uint64_t SAddr; 243 Section.getAddress(SAddr); 244 uint64_t SSize; 245 Section.getSize(SSize); 246 SortedSectionList::iterator It = 247 std::lower_bound(SortedSections.begin(), SortedSections.end(), SAddr, 248 SectionStartsBefore); 249 if (It != SortedSections.end()) { 250 uint64_t FoundSAddr; It->getAddress(FoundSAddr); 251 if (FoundSAddr < SAddr + SSize) 252 llvm_unreachable("Inserting overlapping sections"); 253 } 254 SortedSections.insert(It, Section); 255 } 256 } 257 258 void MCObjectSymbolizer::buildRelocationByAddrMap() { 259 for (const SectionRef &Section : Obj->sections()) { 260 for (const RelocationRef &Reloc : Section.relocations()) { 261 uint64_t Address; 262 Reloc.getAddress(Address); 263 // At a specific address, only keep the first relocation. 264 if (AddrToReloc.find(Address) == AddrToReloc.end()) 265 AddrToReloc[Address] = Reloc; 266 } 267 } 268 } 269