1139749Simp//===-- lib/MC/MCObjectSymbolizer.cpp -------------------------------------===// 2117632Sharti// 3117632Sharti// The LLVM Compiler Infrastructure 4117632Sharti// 5117632Sharti// This file is distributed under the University of Illinois Open Source 6117632Sharti// License. See LICENSE.TXT for details. 7117632Sharti// 8117632Sharti//===----------------------------------------------------------------------===// 9117632Sharti 10117632Sharti#include "llvm/MC/MCObjectSymbolizer.h" 11117632Sharti#include "llvm/ADT/SmallString.h" 12117632Sharti#include "llvm/MC/MCContext.h" 13117632Sharti#include "llvm/MC/MCExpr.h" 14117632Sharti#include "llvm/MC/MCInst.h" 15117632Sharti#include "llvm/MC/MCRelocationInfo.h" 16117632Sharti#include "llvm/MC/MCSymbol.h" 17117632Sharti#include "llvm/Object/MachO.h" 18117632Sharti#include "llvm/Object/ELFObjectFile.h" 19117632Sharti#include "llvm/Support/raw_ostream.h" 20117632Sharti#include <algorithm> 21117632Sharti 22117632Shartiusing namespace llvm; 23117632Shartiusing namespace object; 24117632Sharti 25117632Sharti//===- MCMachObjectSymbolizer ---------------------------------------------===// 26117632Sharti 27117632Shartinamespace { 28117632Sharticlass MCMachObjectSymbolizer : public MCObjectSymbolizer { 29117632Sharti const MachOObjectFile *MOOF; 30117632Sharti // __TEXT;__stubs support. 31117632Sharti uint64_t StubsStart; 32117632Sharti uint64_t StubsCount; 33117632Sharti uint64_t StubSize; 34117632Sharti uint64_t StubsIndSymIndex; 35117632Sharti 36117632Shartipublic: 37117632Sharti MCMachObjectSymbolizer(MCContext &Ctx, OwningPtr<MCRelocationInfo> &RelInfo, 38117632Sharti const MachOObjectFile *MOOF); 39117632Sharti 40117632Sharti StringRef findExternalFunctionAt(uint64_t Addr) LLVM_OVERRIDE; 41117632Sharti 42117632Sharti void tryAddingPcLoadReferenceComment(raw_ostream &cStream, 43117632Sharti int64_t Value, 44117632Sharti uint64_t Address) LLVM_OVERRIDE; 45117632Sharti}; 46117632Sharti} // End unnamed namespace 47117632Sharti 48117632Sharti 49117632ShartiMCMachObjectSymbolizer:: 50117632ShartiMCMachObjectSymbolizer(MCContext &Ctx, OwningPtr<MCRelocationInfo> &RelInfo, 51117632Sharti const MachOObjectFile *MOOF) 52117632Sharti : MCObjectSymbolizer(Ctx, RelInfo, MOOF), MOOF(MOOF), 53117632Sharti StubsStart(0), StubsCount(0), StubSize(0), StubsIndSymIndex(0) { 54117632Sharti 55117632Sharti error_code ec; 56117632Sharti for (section_iterator SI = MOOF->begin_sections(), SE = MOOF->end_sections(); 57117632Sharti SI != SE; SI.increment(ec)) { 58117632Sharti if (ec) break; 59117632Sharti StringRef Name; SI->getName(Name); 60117632Sharti if (Name == "__stubs") { 61117632Sharti SectionRef StubsSec = *SI; 62117632Sharti if (MOOF->is64Bit()) { 63117632Sharti MachO::section_64 S = MOOF->getSection64(StubsSec.getRawDataRefImpl()); 64117632Sharti StubsIndSymIndex = S.reserved1; 65117632Sharti StubSize = S.reserved2; 66117632Sharti } else { 67117632Sharti MachO::section S = MOOF->getSection(StubsSec.getRawDataRefImpl()); 68117632Sharti StubsIndSymIndex = S.reserved1; 69117632Sharti StubSize = S.reserved2; 70117632Sharti } 71117632Sharti assert(StubSize && "Mach-O stub entry size can't be zero!"); 72117632Sharti StubsSec.getAddress(StubsStart); 73117632Sharti StubsSec.getSize(StubsCount); 74117632Sharti StubsCount /= StubSize; 75117632Sharti } 76117632Sharti } 77117632Sharti} 78117632Sharti 79117632ShartiStringRef MCMachObjectSymbolizer::findExternalFunctionAt(uint64_t Addr) { 80117632Sharti // FIXME: also, this can all be done at the very beginning, by iterating over 81117632Sharti // all stubs and creating the calls to outside functions. Is it worth it 82117632Sharti // though? 83117632Sharti if (!StubSize) 84117632Sharti return StringRef(); 85117632Sharti uint64_t StubIdx = (Addr - StubsStart) / StubSize; 86117632Sharti if (StubIdx >= StubsCount) 87117632Sharti return StringRef(); 88117632Sharti 89117632Sharti uint32_t SymtabIdx = 90117632Sharti MOOF->getIndirectSymbolTableEntry(MOOF->getDysymtabLoadCommand(), StubIdx); 91117632Sharti 92117632Sharti StringRef SymName; 93117632Sharti symbol_iterator SI = MOOF->begin_symbols(); 94117632Sharti error_code ec; 95117632Sharti for (uint32_t i = 0; i != SymtabIdx; ++i) { 96117632Sharti SI.increment(ec); 97117632Sharti } 98117632Sharti SI->getName(SymName); 99117632Sharti assert(SI != MOOF->end_symbols() && "Stub wasn't found in the symbol table!"); 100117632Sharti assert(SymName.front() == '_' && "Mach-O symbol doesn't start with '_'!"); 101117632Sharti return SymName.substr(1); 102117632Sharti} 103117632Sharti 104117632Shartivoid MCMachObjectSymbolizer:: 105117632ShartitryAddingPcLoadReferenceComment(raw_ostream &cStream, int64_t Value, 106117632Sharti uint64_t Address) { 107117632Sharti if (const RelocationRef *R = findRelocationAt(Address)) { 108117632Sharti const MCExpr *RelExpr = RelInfo->createExprForRelocation(*R); 109117632Sharti if (!RelExpr || RelExpr->EvaluateAsAbsolute(Value) == false) 110117632Sharti return; 111117632Sharti } 112117632Sharti uint64_t Addr = Value; 113117632Sharti if (const SectionRef *S = findSectionContaining(Addr)) { 114117632Sharti StringRef Name; S->getName(Name); 115117632Sharti uint64_t SAddr; S->getAddress(SAddr); 116117632Sharti if (Name == "__cstring") { 117117632Sharti StringRef Contents; 118117632Sharti S->getContents(Contents); 119117632Sharti Contents = Contents.substr(Addr - SAddr); 120117632Sharti cStream << " ## literal pool for: " 121117632Sharti << Contents.substr(0, Contents.find_first_of(0)); 122117632Sharti } 123117632Sharti } 124117632Sharti} 125117632Sharti 126117632Sharti//===- MCObjectSymbolizer -------------------------------------------------===// 127117632Sharti 128117632ShartiMCObjectSymbolizer::MCObjectSymbolizer(MCContext &Ctx, 129117632Sharti OwningPtr<MCRelocationInfo> &RelInfo, 130117632Sharti const ObjectFile *Obj) 131117632Sharti : MCSymbolizer(Ctx, RelInfo), Obj(Obj), SortedSections(), AddrToReloc() { 132117632Sharti} 133117632Sharti 134117632Shartibool MCObjectSymbolizer:: 135117632ShartitryAddingSymbolicOperand(MCInst &MI, raw_ostream &cStream, 136117632Sharti int64_t Value, uint64_t Address, bool IsBranch, 137117632Sharti uint64_t Offset, uint64_t InstSize) { 138117632Sharti if (IsBranch) { 139117632Sharti StringRef ExtFnName = findExternalFunctionAt((uint64_t)Value); 140117632Sharti if (!ExtFnName.empty()) { 141117632Sharti MCSymbol *Sym = Ctx.GetOrCreateSymbol(ExtFnName); 142117632Sharti const MCExpr *Expr = MCSymbolRefExpr::Create(Sym, Ctx); 143117632Sharti MI.addOperand(MCOperand::CreateExpr(Expr)); 144117632Sharti return true; 145117632Sharti } 146117632Sharti } 147117632Sharti 148117632Sharti if (const RelocationRef *R = findRelocationAt(Address + Offset)) { 149117632Sharti if (const MCExpr *RelExpr = RelInfo->createExprForRelocation(*R)) { 150117632Sharti MI.addOperand(MCOperand::CreateExpr(RelExpr)); 151117632Sharti return true; 152147256Sbrooks } 153117632Sharti // Only try to create a symbol+offset expression if there is no relocation. 154117632Sharti return false; 155117632Sharti } 156117632Sharti 157117632Sharti // Interpret Value as a branch target. 158117632Sharti if (IsBranch == false) 159117632Sharti return false; 160117632Sharti uint64_t UValue = Value; 161117632Sharti // FIXME: map instead of looping each time? 162117632Sharti error_code ec; 163117632Sharti for (symbol_iterator SI = Obj->begin_symbols(), SE = Obj->end_symbols(); 164117632Sharti SI != SE; SI.increment(ec)) { 165117632Sharti if (ec) break; 166117632Sharti uint64_t SymAddr; SI->getAddress(SymAddr); 167117632Sharti uint64_t SymSize; SI->getSize(SymSize); 168117632Sharti StringRef SymName; SI->getName(SymName); 169117632Sharti SymbolRef::Type SymType; SI->getType(SymType); 170117632Sharti if (SymAddr == UnknownAddressOrSize || SymSize == UnknownAddressOrSize 171117632Sharti || SymName.empty() || SymType != SymbolRef::ST_Function) 172117632Sharti continue; 173117632Sharti 174117632Sharti if ( SymAddr == UValue || 175117632Sharti (SymAddr <= UValue && SymAddr + SymSize > UValue)) { 176117632Sharti MCSymbol *Sym = Ctx.GetOrCreateSymbol(SymName); 177117632Sharti const MCExpr *Expr = MCSymbolRefExpr::Create(Sym, Ctx); 178117632Sharti if (SymAddr != UValue) { 179117632Sharti const MCExpr *Off = MCConstantExpr::Create(UValue - SymAddr, Ctx); 180117632Sharti Expr = MCBinaryExpr::CreateAdd(Expr, Off, Ctx); 181117632Sharti } 182117632Sharti MI.addOperand(MCOperand::CreateExpr(Expr)); 183117632Sharti return true; 184117632Sharti } 185117632Sharti } 186117632Sharti return false; 187117632Sharti} 188117632Sharti 189117632Shartivoid MCObjectSymbolizer:: 190117632ShartitryAddingPcLoadReferenceComment(raw_ostream &cStream, 191117632Sharti int64_t Value, uint64_t Address) { 192117632Sharti} 193117632Sharti 194117632ShartiStringRef MCObjectSymbolizer::findExternalFunctionAt(uint64_t Addr) { 195117632Sharti return StringRef(); 196117632Sharti} 197117632Sharti 198117632ShartiMCObjectSymbolizer * 199118601ShartiMCObjectSymbolizer::createObjectSymbolizer(MCContext &Ctx, 200117632Sharti OwningPtr<MCRelocationInfo> &RelInfo, 201117632Sharti const ObjectFile *Obj) { 202117632Sharti if (const MachOObjectFile *MOOF = dyn_cast<MachOObjectFile>(Obj)) 203117632Sharti return new MCMachObjectSymbolizer(Ctx, RelInfo, MOOF); 204117632Sharti return new MCObjectSymbolizer(Ctx, RelInfo, Obj); 205117632Sharti} 206117632Sharti 207117632Sharti// SortedSections implementation. 208117632Sharti 209117632Shartistatic bool SectionStartsBefore(const SectionRef &S, uint64_t Addr) { 210117632Sharti uint64_t SAddr; S.getAddress(SAddr); 211117632Sharti return SAddr < Addr; 212117632Sharti} 213117632Sharti 214117632Sharticonst SectionRef *MCObjectSymbolizer::findSectionContaining(uint64_t Addr) { 215117632Sharti if (SortedSections.empty()) 216117632Sharti buildSectionList(); 217117632Sharti 218117632Sharti SortedSectionList::iterator 219117632Sharti EndIt = SortedSections.end(), 220117632Sharti It = std::lower_bound(SortedSections.begin(), EndIt, 221147256Sbrooks Addr, SectionStartsBefore); 222117632Sharti if (It == EndIt) 223117632Sharti return 0; 224117632Sharti uint64_t SAddr; It->getAddress(SAddr); 225117632Sharti uint64_t SSize; It->getSize(SSize); 226117632Sharti if (Addr >= SAddr + SSize) 227117632Sharti return 0; 228117632Sharti return &*It; 229117632Sharti} 230117632Sharti 231117632Sharticonst RelocationRef *MCObjectSymbolizer::findRelocationAt(uint64_t Addr) { 232117632Sharti if (AddrToReloc.empty()) 233117632Sharti buildRelocationByAddrMap(); 234117632Sharti 235117632Sharti AddrToRelocMap::const_iterator RI = AddrToReloc.find(Addr); 236117632Sharti if (RI == AddrToReloc.end()) 237117632Sharti return 0; 238117632Sharti return &RI->second; 239117632Sharti} 240117632Sharti 241117632Shartivoid MCObjectSymbolizer::buildSectionList() { 242117632Sharti error_code ec; 243117632Sharti for (section_iterator SI = Obj->begin_sections(), SE = Obj->end_sections(); 244117632Sharti SI != SE; SI.increment(ec)) { 245117632Sharti if (ec) break; 246117632Sharti 247117632Sharti bool RequiredForExec; SI->isRequiredForExecution(RequiredForExec); 248117632Sharti if (RequiredForExec == false) 249117632Sharti continue; 250117632Sharti uint64_t SAddr; SI->getAddress(SAddr); 251117632Sharti uint64_t SSize; SI->getSize(SSize); 252117632Sharti SortedSectionList::iterator It = std::lower_bound(SortedSections.begin(), 253117632Sharti SortedSections.end(), 254117632Sharti SAddr, 255117632Sharti SectionStartsBefore); 256117632Sharti if (It != SortedSections.end()) { 257117632Sharti uint64_t FoundSAddr; It->getAddress(FoundSAddr); 258117632Sharti if (FoundSAddr < SAddr + SSize) 259117632Sharti llvm_unreachable("Inserting overlapping sections"); 260117632Sharti } 261117632Sharti SortedSections.insert(It, *SI); 262117632Sharti } 263117632Sharti} 264117632Sharti 265117632Shartivoid MCObjectSymbolizer::buildRelocationByAddrMap() { 266117632Sharti error_code ec; 267117632Sharti for (section_iterator SI = Obj->begin_sections(), SE = Obj->end_sections(); 268117632Sharti SI != SE; SI.increment(ec)) { 269117632Sharti if (ec) break; 270117632Sharti 271117632Sharti section_iterator RelSecI = SI->getRelocatedSection(); 272117632Sharti if (RelSecI == Obj->end_sections()) 273117632Sharti continue; 274117632Sharti 275117632Sharti uint64_t StartAddr; RelSecI->getAddress(StartAddr); 276117632Sharti uint64_t Size; RelSecI->getSize(Size); 277117632Sharti bool RequiredForExec; RelSecI->isRequiredForExecution(RequiredForExec); 278117632Sharti if (RequiredForExec == false || Size == 0) 279117632Sharti continue; 280117632Sharti for (relocation_iterator RI = SI->begin_relocations(), 281117632Sharti RE = SI->end_relocations(); 282117632Sharti RI != RE; 283117632Sharti RI.increment(ec)) { 284117632Sharti if (ec) break; 285117632Sharti // FIXME: libObject is inconsistent regarding error handling. The 286117632Sharti // overwhelming majority of methods always return object_error::success, 287117632Sharti // and assert for simple errors.. Here, ELFObjectFile::getRelocationOffset 288117632Sharti // asserts when the file type isn't ET_REL. 289117632Sharti // This workaround handles x86-64 elf, the only one that has a relocinfo. 290117632Sharti uint64_t Offset; 291117632Sharti if (Obj->isELF()) { 292117632Sharti const ELF64LEObjectFile *ELFObj = dyn_cast<ELF64LEObjectFile>(Obj); 293117632Sharti if (ELFObj == 0) 294117632Sharti break; 295117632Sharti if (ELFObj->getELFFile()->getHeader()->e_type == ELF::ET_REL) { 296117632Sharti RI->getOffset(Offset); 297117632Sharti Offset += StartAddr; 298117632Sharti } else { 299117632Sharti RI->getAddress(Offset); 300117632Sharti } 301117632Sharti } else { 302117632Sharti RI->getOffset(Offset); 303117632Sharti Offset += StartAddr; 304117632Sharti } 305117632Sharti // At a specific address, only keep the first relocation. 306117632Sharti if (AddrToReloc.find(Offset) == AddrToReloc.end()) 307117632Sharti AddrToReloc[Offset] = *RI; 308117632Sharti } 309117632Sharti } 310117632Sharti} 311117632Sharti