b9131d1ed6091616a70bf53e5f292e6332432760
[oota-llvm.git] / lib / MC / MCObjectSymbolizer.cpp
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/MachO.h"
18 #include "llvm/Object/ELFObjectFile.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, OwningPtr<MCRelocationInfo> &RelInfo,
38                          const MachOObjectFile *MOOF);
39
40   StringRef findExternalFunctionAt(uint64_t Addr) LLVM_OVERRIDE;
41
42   void tryAddingPcLoadReferenceComment(raw_ostream &cStream,
43                                        int64_t Value,
44                                        uint64_t Address) LLVM_OVERRIDE;
45 };
46 } // End unnamed namespace
47
48
49 MCMachObjectSymbolizer::
50 MCMachObjectSymbolizer(MCContext &Ctx, OwningPtr<MCRelocationInfo> &RelInfo,
51                        const MachOObjectFile *MOOF)
52     : MCObjectSymbolizer(Ctx, RelInfo, MOOF), MOOF(MOOF),
53       StubsStart(0), StubsCount(0), StubSize(0), StubsIndSymIndex(0) {
54
55   error_code ec;
56   for (section_iterator SI = MOOF->begin_sections(), SE = MOOF->end_sections();
57        SI != SE; SI.increment(ec)) {
58     if (ec) break;
59     StringRef Name; SI->getName(Name);
60     if (Name == "__stubs") {
61       SectionRef StubsSec = *SI;
62       if (MOOF->is64Bit()) {
63         MachO::section_64 S = MOOF->getSection64(StubsSec.getRawDataRefImpl());
64         StubsIndSymIndex = S.reserved1;
65         StubSize = S.reserved2;
66       } else {
67         MachO::section S = MOOF->getSection(StubsSec.getRawDataRefImpl());
68         StubsIndSymIndex = S.reserved1;
69         StubSize = S.reserved2;
70       }
71       assert(StubSize && "Mach-O stub entry size can't be zero!");
72       StubsSec.getAddress(StubsStart);
73       StubsSec.getSize(StubsCount);
74       StubsCount /= StubSize;
75     }
76   }
77 }
78
79 StringRef MCMachObjectSymbolizer::findExternalFunctionAt(uint64_t Addr) {
80   // FIXME: also, this can all be done at the very beginning, by iterating over
81   // all stubs and creating the calls to outside functions. Is it worth it
82   // though?
83   if (!StubSize)
84     return StringRef();
85   uint64_t StubIdx = (Addr - StubsStart) / StubSize;
86   if (StubIdx >= StubsCount)
87     return StringRef();
88
89   uint32_t SymtabIdx =
90     MOOF->getIndirectSymbolTableEntry(MOOF->getDysymtabLoadCommand(), StubIdx);
91
92   StringRef SymName;
93   symbol_iterator SI = MOOF->begin_symbols();
94   error_code ec;
95   for (uint32_t i = 0; i != SymtabIdx; ++i) {
96     SI.increment(ec);
97   }
98   SI->getName(SymName);
99   assert(SI != MOOF->end_symbols() && "Stub wasn't found in the symbol table!");
100   assert(SymName.front() == '_' && "Mach-O symbol doesn't start with '_'!");
101   return SymName.substr(1);
102 }
103
104 void MCMachObjectSymbolizer::
105 tryAddingPcLoadReferenceComment(raw_ostream &cStream, int64_t Value,
106                                 uint64_t Address) {
107   if (const RelocationRef *R = findRelocationAt(Address)) {
108     const MCExpr *RelExpr = RelInfo->createExprForRelocation(*R);
109     if (!RelExpr || RelExpr->EvaluateAsAbsolute(Value) == false)
110       return;
111   }
112   uint64_t Addr = Value;
113   if (const SectionRef *S = findSectionContaining(Addr)) {
114     StringRef Name; S->getName(Name);
115     uint64_t SAddr; S->getAddress(SAddr);
116     if (Name == "__cstring") {
117       StringRef Contents;
118       S->getContents(Contents);
119       Contents = Contents.substr(Addr - SAddr);
120       cStream << " ## literal pool for: "
121               << Contents.substr(0, Contents.find_first_of(0));
122     }
123   }
124 }
125
126 //===- MCObjectSymbolizer -------------------------------------------------===//
127
128 MCObjectSymbolizer::MCObjectSymbolizer(MCContext &Ctx,
129                                        OwningPtr<MCRelocationInfo> &RelInfo,
130                                        const ObjectFile *Obj)
131     : MCSymbolizer(Ctx, RelInfo), Obj(Obj), SortedSections(), AddrToReloc() {
132 }
133
134 bool MCObjectSymbolizer::
135 tryAddingSymbolicOperand(MCInst &MI, raw_ostream &cStream,
136                          int64_t Value, uint64_t Address, bool IsBranch,
137                          uint64_t Offset, uint64_t InstSize) {
138   if (IsBranch) {
139     StringRef ExtFnName = findExternalFunctionAt((uint64_t)Value);
140     if (!ExtFnName.empty()) {
141       MCSymbol *Sym = Ctx.GetOrCreateSymbol(ExtFnName);
142       const MCExpr *Expr = MCSymbolRefExpr::Create(Sym, Ctx);
143       MI.addOperand(MCOperand::CreateExpr(Expr));
144       return true;
145     }
146   }
147
148   if (const RelocationRef *R = findRelocationAt(Address + Offset)) {
149     if (const MCExpr *RelExpr = RelInfo->createExprForRelocation(*R)) {
150       MI.addOperand(MCOperand::CreateExpr(RelExpr));
151       return true;
152     }
153     // Only try to create a symbol+offset expression if there is no relocation.
154     return false;
155   }
156
157   // Interpret Value as a branch target.
158   if (IsBranch == false)
159     return false;
160   uint64_t UValue = Value;
161   // FIXME: map instead of looping each time?
162   error_code ec;
163   for (symbol_iterator SI = Obj->begin_symbols(), SE = Obj->end_symbols();
164        SI != SE; SI.increment(ec)) {
165     if (ec) break;
166     uint64_t SymAddr; SI->getAddress(SymAddr);
167     uint64_t SymSize; SI->getSize(SymSize);
168     StringRef SymName; SI->getName(SymName);
169     SymbolRef::Type SymType; SI->getType(SymType);
170     if (SymAddr == UnknownAddressOrSize || SymSize == UnknownAddressOrSize
171         || SymName.empty() || SymType != SymbolRef::ST_Function)
172       continue;
173
174     if ( SymAddr == UValue ||
175         (SymAddr <= UValue && SymAddr + SymSize > UValue)) {
176       MCSymbol *Sym = Ctx.GetOrCreateSymbol(SymName);
177       const MCExpr *Expr = MCSymbolRefExpr::Create(Sym, Ctx);
178       if (SymAddr != UValue) {
179         const MCExpr *Off = MCConstantExpr::Create(UValue - SymAddr, Ctx);
180         Expr = MCBinaryExpr::CreateAdd(Expr, Off, Ctx);
181       }
182       MI.addOperand(MCOperand::CreateExpr(Expr));
183       return true;
184     }
185   }
186   return false;
187 }
188
189 void MCObjectSymbolizer::
190 tryAddingPcLoadReferenceComment(raw_ostream &cStream,
191                                 int64_t Value, uint64_t Address) {
192 }
193
194 StringRef MCObjectSymbolizer::findExternalFunctionAt(uint64_t Addr) {
195   return StringRef();
196 }
197
198 MCObjectSymbolizer *
199 MCObjectSymbolizer::createObjectSymbolizer(MCContext &Ctx,
200                                            OwningPtr<MCRelocationInfo> &RelInfo,
201                                            const ObjectFile *Obj) {
202   if (const MachOObjectFile *MOOF = dyn_cast<MachOObjectFile>(Obj))
203     return new MCMachObjectSymbolizer(Ctx, RelInfo, MOOF);
204   return new MCObjectSymbolizer(Ctx, RelInfo, Obj);
205 }
206
207 // SortedSections implementation.
208
209 static bool SectionStartsBefore(const SectionRef &S, uint64_t Addr) {
210   uint64_t SAddr; S.getAddress(SAddr);
211   return SAddr < Addr;
212 }
213
214 const SectionRef *MCObjectSymbolizer::findSectionContaining(uint64_t Addr) {
215   if (SortedSections.empty())
216     buildSectionList();
217
218   SortedSectionList::iterator
219     EndIt = SortedSections.end(),
220     It = std::lower_bound(SortedSections.begin(), EndIt,
221                           Addr, SectionStartsBefore);
222   if (It == EndIt)
223     return 0;
224   uint64_t SAddr; It->getAddress(SAddr);
225   uint64_t SSize; It->getSize(SSize);
226   if (Addr >= SAddr + SSize)
227     return 0;
228   return &*It;
229 }
230
231 const RelocationRef *MCObjectSymbolizer::findRelocationAt(uint64_t Addr) {
232   if (AddrToReloc.empty())
233     buildRelocationByAddrMap();
234
235   AddrToRelocMap::const_iterator RI = AddrToReloc.find(Addr);
236   if (RI == AddrToReloc.end())
237     return 0;
238   return &RI->second;
239 }
240
241 void MCObjectSymbolizer::buildSectionList() {
242   error_code ec;
243   for (section_iterator SI = Obj->begin_sections(), SE = Obj->end_sections();
244                         SI != SE; SI.increment(ec)) {
245     if (ec) break;
246
247     bool RequiredForExec; SI->isRequiredForExecution(RequiredForExec);
248     if (RequiredForExec == false)
249       continue;
250     uint64_t SAddr; SI->getAddress(SAddr);
251     uint64_t SSize; SI->getSize(SSize);
252     SortedSectionList::iterator It = std::lower_bound(SortedSections.begin(),
253                                                       SortedSections.end(),
254                                                       SAddr,
255                                                       SectionStartsBefore);
256     if (It != SortedSections.end()) {
257       uint64_t FoundSAddr; It->getAddress(FoundSAddr);
258       if (FoundSAddr < SAddr + SSize)
259         llvm_unreachable("Inserting overlapping sections");
260     }
261     SortedSections.insert(It, *SI);
262   }
263 }
264
265 void MCObjectSymbolizer::buildRelocationByAddrMap() {
266   error_code ec;
267   for (section_iterator SI = Obj->begin_sections(), SE = Obj->end_sections();
268                         SI != SE; SI.increment(ec)) {
269     if (ec) break;
270
271     section_iterator RelSecI = SI->getRelocatedSection();
272     if (RelSecI == Obj->end_sections())
273       continue;
274
275     uint64_t StartAddr; RelSecI->getAddress(StartAddr);
276     uint64_t Size; RelSecI->getSize(Size);
277     bool RequiredForExec; RelSecI->isRequiredForExecution(RequiredForExec);
278     if (RequiredForExec == false || Size == 0)
279       continue;
280     for (relocation_iterator RI = SI->begin_relocations(),
281                              RE = SI->end_relocations();
282                              RI != RE;
283                              RI.increment(ec)) {
284       if (ec) break;
285       // FIXME: libObject is inconsistent regarding error handling. The
286       // overwhelming majority of methods always return object_error::success,
287       // and assert for simple errors.. Here, ELFObjectFile::getRelocationOffset
288       // asserts when the file type isn't ET_REL.
289       // This workaround handles x86-64 elf, the only one that has a relocinfo.
290       uint64_t Offset;
291       if (Obj->isELF()) {
292         const ELF64LEObjectFile *ELFObj = dyn_cast<ELF64LEObjectFile>(Obj);
293         if (ELFObj == 0)
294           break;
295         if (ELFObj->getELFFile()->getHeader()->e_type == ELF::ET_REL) {
296           RI->getOffset(Offset);
297           Offset += StartAddr;
298         } else {
299           RI->getAddress(Offset);
300         }
301       } else {
302         RI->getOffset(Offset);
303         Offset += StartAddr;
304       }
305       // At a specific address, only keep the first relocation.
306       if (AddrToReloc.find(Offset) == AddrToReloc.end())
307         AddrToReloc[Offset] = *RI;
308     }
309   }
310 }