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