MachOObjectFile.cpp revision 790552c20fbd8daa77d343419f0f6ec4e7fa1457
1//===- MachOObjectFile.cpp - Mach-O object file binding ---------*- C++ -*-===//
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// This file defines the MachOObjectFile class, which binds the MachOObject
11// class to the generic ObjectFile wrapper.
12//
13//===----------------------------------------------------------------------===//
14
15#include "llvm/ADT/Triple.h"
16#include "llvm/Object/MachO.h"
17#include "llvm/Object/MachOFormat.h"
18#include "llvm/Support/Format.h"
19#include "llvm/Support/MemoryBuffer.h"
20
21#include <cctype>
22#include <cstring>
23#include <limits>
24
25using namespace llvm;
26using namespace object;
27
28namespace llvm {
29namespace object {
30
31MachOObjectFile::MachOObjectFile(MemoryBuffer *Object, MachOObject *MOO,
32                                 error_code &ec)
33    : ObjectFile(Binary::isMachO, Object, ec),
34      MachOObj(MOO),
35      RegisteredStringTable(std::numeric_limits<uint32_t>::max()) {
36  DataRefImpl DRI;
37  DRI.d.a = DRI.d.b = 0;
38  moveToNextSection(DRI);
39  uint32_t LoadCommandCount = MachOObj->getHeader().NumLoadCommands;
40  while (DRI.d.a < LoadCommandCount) {
41    Sections.push_back(DRI);
42    DRI.d.b++;
43    moveToNextSection(DRI);
44  }
45}
46
47
48ObjectFile *ObjectFile::createMachOObjectFile(MemoryBuffer *Buffer) {
49  error_code ec;
50  std::string Err;
51  MachOObject *MachOObj = MachOObject::LoadFromBuffer(Buffer, &Err);
52  if (!MachOObj)
53    return NULL;
54  return new MachOObjectFile(Buffer, MachOObj, ec);
55}
56
57/*===-- Symbols -----------------------------------------------------------===*/
58
59void MachOObjectFile::moveToNextSymbol(DataRefImpl &DRI) const {
60  uint32_t LoadCommandCount = MachOObj->getHeader().NumLoadCommands;
61  while (DRI.d.a < LoadCommandCount) {
62    LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a);
63    if (LCI.Command.Type == macho::LCT_Symtab) {
64      InMemoryStruct<macho::SymtabLoadCommand> SymtabLoadCmd;
65      MachOObj->ReadSymtabLoadCommand(LCI, SymtabLoadCmd);
66      if (DRI.d.b < SymtabLoadCmd->NumSymbolTableEntries)
67        return;
68    }
69
70    DRI.d.a++;
71    DRI.d.b = 0;
72  }
73}
74
75void MachOObjectFile::getSymbolTableEntry(DataRefImpl DRI,
76    InMemoryStruct<macho::SymbolTableEntry> &Res) const {
77  InMemoryStruct<macho::SymtabLoadCommand> SymtabLoadCmd;
78  LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a);
79  MachOObj->ReadSymtabLoadCommand(LCI, SymtabLoadCmd);
80
81  if (RegisteredStringTable != DRI.d.a) {
82    MachOObj->RegisterStringTable(*SymtabLoadCmd);
83    RegisteredStringTable = DRI.d.a;
84  }
85
86  MachOObj->ReadSymbolTableEntry(SymtabLoadCmd->SymbolTableOffset, DRI.d.b,
87                                 Res);
88}
89
90void MachOObjectFile::getSymbol64TableEntry(DataRefImpl DRI,
91    InMemoryStruct<macho::Symbol64TableEntry> &Res) const {
92  InMemoryStruct<macho::SymtabLoadCommand> SymtabLoadCmd;
93  LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a);
94  MachOObj->ReadSymtabLoadCommand(LCI, SymtabLoadCmd);
95
96  if (RegisteredStringTable != DRI.d.a) {
97    MachOObj->RegisterStringTable(*SymtabLoadCmd);
98    RegisteredStringTable = DRI.d.a;
99  }
100
101  MachOObj->ReadSymbol64TableEntry(SymtabLoadCmd->SymbolTableOffset, DRI.d.b,
102                                   Res);
103}
104
105
106error_code MachOObjectFile::getSymbolNext(DataRefImpl DRI,
107                                          SymbolRef &Result) const {
108  DRI.d.b++;
109  moveToNextSymbol(DRI);
110  Result = SymbolRef(DRI, this);
111  return object_error::success;
112}
113
114error_code MachOObjectFile::getSymbolName(DataRefImpl DRI,
115                                          StringRef &Result) const {
116  if (MachOObj->is64Bit()) {
117    InMemoryStruct<macho::Symbol64TableEntry> Entry;
118    getSymbol64TableEntry(DRI, Entry);
119    Result = MachOObj->getStringAtIndex(Entry->StringIndex);
120  } else {
121    InMemoryStruct<macho::SymbolTableEntry> Entry;
122    getSymbolTableEntry(DRI, Entry);
123    Result = MachOObj->getStringAtIndex(Entry->StringIndex);
124  }
125  return object_error::success;
126}
127
128error_code MachOObjectFile::getSymbolOffset(DataRefImpl DRI,
129                                             uint64_t &Result) const {
130  uint64_t SectionOffset;
131  uint8_t SectionIndex;
132  if (MachOObj->is64Bit()) {
133    InMemoryStruct<macho::Symbol64TableEntry> Entry;
134    getSymbol64TableEntry(DRI, Entry);
135    Result = Entry->Value;
136    SectionIndex = Entry->SectionIndex;
137  } else {
138    InMemoryStruct<macho::SymbolTableEntry> Entry;
139    getSymbolTableEntry(DRI, Entry);
140    Result = Entry->Value;
141    SectionIndex = Entry->SectionIndex;
142  }
143  getSectionAddress(Sections[SectionIndex-1], SectionOffset);
144  Result -= SectionOffset;
145
146  return object_error::success;
147}
148
149error_code MachOObjectFile::getSymbolAddress(DataRefImpl DRI,
150                                             uint64_t &Result) const {
151  if (MachOObj->is64Bit()) {
152    InMemoryStruct<macho::Symbol64TableEntry> Entry;
153    getSymbol64TableEntry(DRI, Entry);
154    Result = Entry->Value;
155  } else {
156    InMemoryStruct<macho::SymbolTableEntry> Entry;
157    getSymbolTableEntry(DRI, Entry);
158    Result = Entry->Value;
159  }
160  return object_error::success;
161}
162
163error_code MachOObjectFile::getSymbolSize(DataRefImpl DRI,
164                                          uint64_t &Result) const {
165  Result = UnknownAddressOrSize;
166  return object_error::success;
167}
168
169error_code MachOObjectFile::getSymbolNMTypeChar(DataRefImpl DRI,
170                                                char &Result) const {
171  uint8_t Type, Flags;
172  if (MachOObj->is64Bit()) {
173    InMemoryStruct<macho::Symbol64TableEntry> Entry;
174    getSymbol64TableEntry(DRI, Entry);
175    Type = Entry->Type;
176    Flags = Entry->Flags;
177  } else {
178    InMemoryStruct<macho::SymbolTableEntry> Entry;
179    getSymbolTableEntry(DRI, Entry);
180    Type = Entry->Type;
181    Flags = Entry->Flags;
182  }
183
184  char Char;
185  switch (Type & macho::STF_TypeMask) {
186    case macho::STT_Undefined:
187      Char = 'u';
188      break;
189    case macho::STT_Absolute:
190    case macho::STT_Section:
191      Char = 's';
192      break;
193    default:
194      Char = '?';
195      break;
196  }
197
198  if (Flags & (macho::STF_External | macho::STF_PrivateExtern))
199    Char = toupper(Char);
200  Result = Char;
201  return object_error::success;
202}
203
204error_code MachOObjectFile::isSymbolInternal(DataRefImpl DRI,
205                                             bool &Result) const {
206  if (MachOObj->is64Bit()) {
207    InMemoryStruct<macho::Symbol64TableEntry> Entry;
208    getSymbol64TableEntry(DRI, Entry);
209    Result = Entry->Flags & macho::STF_StabsEntryMask;
210  } else {
211    InMemoryStruct<macho::SymbolTableEntry> Entry;
212    getSymbolTableEntry(DRI, Entry);
213    Result = Entry->Flags & macho::STF_StabsEntryMask;
214  }
215  return object_error::success;
216}
217
218error_code MachOObjectFile::isSymbolGlobal(DataRefImpl Symb, bool &Res) const {
219
220  if (MachOObj->is64Bit()) {
221    InMemoryStruct<macho::Symbol64TableEntry> Entry;
222    getSymbol64TableEntry(Symb, Entry);
223    Res = Entry->Type & MachO::NlistMaskExternal;
224  } else {
225    InMemoryStruct<macho::SymbolTableEntry> Entry;
226    getSymbolTableEntry(Symb, Entry);
227    Res = Entry->Type & MachO::NlistMaskExternal;
228  }
229  return object_error::success;
230}
231
232error_code MachOObjectFile::isSymbolWeak(DataRefImpl Symb, bool &Res) const {
233
234  if (MachOObj->is64Bit()) {
235    InMemoryStruct<macho::Symbol64TableEntry> Entry;
236    getSymbol64TableEntry(Symb, Entry);
237    Res = Entry->Flags & (MachO::NListDescWeakRef | MachO::NListDescWeakDef);
238  } else {
239    InMemoryStruct<macho::SymbolTableEntry> Entry;
240    getSymbolTableEntry(Symb, Entry);
241    Res = Entry->Flags & (MachO::NListDescWeakRef | MachO::NListDescWeakDef);
242  }
243  return object_error::success;
244}
245
246error_code MachOObjectFile::isSymbolAbsolute(DataRefImpl Symb, bool &Res) const{
247  uint8_t n_type;
248  if (MachOObj->is64Bit()) {
249    InMemoryStruct<macho::Symbol64TableEntry> Entry;
250    getSymbol64TableEntry(Symb, Entry);
251    n_type = Entry->Type;
252  } else {
253    InMemoryStruct<macho::SymbolTableEntry> Entry;
254    getSymbolTableEntry(Symb, Entry);
255    n_type = Entry->Type;
256  }
257
258  Res = (n_type & MachO::NlistMaskType) == MachO::NListTypeAbsolute;
259  return object_error::success;
260}
261
262error_code MachOObjectFile::getSymbolSection(DataRefImpl Symb,
263                                             section_iterator &Res) const {
264  uint8_t index;
265  if (MachOObj->is64Bit()) {
266    InMemoryStruct<macho::Symbol64TableEntry> Entry;
267    getSymbol64TableEntry(Symb, Entry);
268    index = Entry->SectionIndex;
269  } else {
270    InMemoryStruct<macho::SymbolTableEntry> Entry;
271    getSymbolTableEntry(Symb, Entry);
272    index = Entry->SectionIndex;
273  }
274
275  if (index == 0)
276    Res = end_sections();
277  else
278    Res = section_iterator(SectionRef(Sections[index], this));
279
280  return object_error::success;
281}
282
283error_code MachOObjectFile::getSymbolType(DataRefImpl Symb,
284                                          SymbolRef::Type &Res) const {
285  uint8_t n_type;
286  if (MachOObj->is64Bit()) {
287    InMemoryStruct<macho::Symbol64TableEntry> Entry;
288    getSymbol64TableEntry(Symb, Entry);
289    n_type = Entry->Type;
290  } else {
291    InMemoryStruct<macho::SymbolTableEntry> Entry;
292    getSymbolTableEntry(Symb, Entry);
293    n_type = Entry->Type;
294  }
295  Res = SymbolRef::ST_Other;
296
297  // If this is a STAB debugging symbol, we can do nothing more.
298  if (n_type & MachO::NlistMaskStab) {
299    Res = SymbolRef::ST_Debug;
300    return object_error::success;
301  }
302
303  switch (n_type & MachO::NlistMaskType) {
304    case MachO::NListTypeUndefined :
305      Res = SymbolRef::ST_External;
306      break;
307    case MachO::NListTypeSection :
308      Res = SymbolRef::ST_Function;
309      break;
310  }
311  return object_error::success;
312}
313
314
315symbol_iterator MachOObjectFile::begin_symbols() const {
316  // DRI.d.a = segment number; DRI.d.b = symbol index.
317  DataRefImpl DRI;
318  DRI.d.a = DRI.d.b = 0;
319  moveToNextSymbol(DRI);
320  return symbol_iterator(SymbolRef(DRI, this));
321}
322
323symbol_iterator MachOObjectFile::end_symbols() const {
324  DataRefImpl DRI;
325  DRI.d.a = MachOObj->getHeader().NumLoadCommands;
326  DRI.d.b = 0;
327  return symbol_iterator(SymbolRef(DRI, this));
328}
329
330
331/*===-- Sections ----------------------------------------------------------===*/
332
333void MachOObjectFile::moveToNextSection(DataRefImpl &DRI) const {
334  uint32_t LoadCommandCount = MachOObj->getHeader().NumLoadCommands;
335  while (DRI.d.a < LoadCommandCount) {
336    LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a);
337    if (LCI.Command.Type == macho::LCT_Segment) {
338      InMemoryStruct<macho::SegmentLoadCommand> SegmentLoadCmd;
339      MachOObj->ReadSegmentLoadCommand(LCI, SegmentLoadCmd);
340      if (DRI.d.b < SegmentLoadCmd->NumSections)
341        return;
342    } else if (LCI.Command.Type == macho::LCT_Segment64) {
343      InMemoryStruct<macho::Segment64LoadCommand> Segment64LoadCmd;
344      MachOObj->ReadSegment64LoadCommand(LCI, Segment64LoadCmd);
345      if (DRI.d.b < Segment64LoadCmd->NumSections)
346        return;
347    }
348
349    DRI.d.a++;
350    DRI.d.b = 0;
351  }
352}
353
354error_code MachOObjectFile::getSectionNext(DataRefImpl DRI,
355                                           SectionRef &Result) const {
356  DRI.d.b++;
357  moveToNextSection(DRI);
358  Result = SectionRef(DRI, this);
359  return object_error::success;
360}
361
362void
363MachOObjectFile::getSection(DataRefImpl DRI,
364                            InMemoryStruct<macho::Section> &Res) const {
365  InMemoryStruct<macho::SegmentLoadCommand> SLC;
366  LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a);
367  MachOObj->ReadSegmentLoadCommand(LCI, SLC);
368  MachOObj->ReadSection(LCI, DRI.d.b, Res);
369}
370
371std::size_t MachOObjectFile::getSectionIndex(DataRefImpl Sec) const {
372  SectionList::const_iterator loc =
373    std::find(Sections.begin(), Sections.end(), Sec);
374  assert(loc != Sections.end() && "Sec is not a valid section!");
375  return std::distance(Sections.begin(), loc);
376}
377
378void
379MachOObjectFile::getSection64(DataRefImpl DRI,
380                            InMemoryStruct<macho::Section64> &Res) const {
381  InMemoryStruct<macho::Segment64LoadCommand> SLC;
382  LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a);
383  MachOObj->ReadSegment64LoadCommand(LCI, SLC);
384  MachOObj->ReadSection64(LCI, DRI.d.b, Res);
385}
386
387static bool is64BitLoadCommand(const MachOObject *MachOObj, DataRefImpl DRI) {
388  LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a);
389  if (LCI.Command.Type == macho::LCT_Segment64)
390    return true;
391  assert(LCI.Command.Type == macho::LCT_Segment && "Unexpected Type.");
392  return false;
393}
394
395error_code MachOObjectFile::getSectionName(DataRefImpl DRI,
396                                           StringRef &Result) const {
397  // FIXME: thread safety.
398  static char result[34];
399  if (is64BitLoadCommand(MachOObj, DRI)) {
400    InMemoryStruct<macho::Segment64LoadCommand> SLC;
401    LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a);
402    MachOObj->ReadSegment64LoadCommand(LCI, SLC);
403    InMemoryStruct<macho::Section64> Sect;
404    MachOObj->ReadSection64(LCI, DRI.d.b, Sect);
405
406    strcpy(result, Sect->SegmentName);
407    strcat(result, ",");
408    strcat(result, Sect->Name);
409  } else {
410    InMemoryStruct<macho::SegmentLoadCommand> SLC;
411    LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a);
412    MachOObj->ReadSegmentLoadCommand(LCI, SLC);
413    InMemoryStruct<macho::Section> Sect;
414    MachOObj->ReadSection(LCI, DRI.d.b, Sect);
415
416    strcpy(result, Sect->SegmentName);
417    strcat(result, ",");
418    strcat(result, Sect->Name);
419  }
420  Result = StringRef(result);
421  return object_error::success;
422}
423
424error_code MachOObjectFile::getSectionAddress(DataRefImpl DRI,
425                                              uint64_t &Result) const {
426  if (is64BitLoadCommand(MachOObj, DRI)) {
427    InMemoryStruct<macho::Section64> Sect;
428    getSection64(DRI, Sect);
429    Result = Sect->Address;
430  } else {
431    InMemoryStruct<macho::Section> Sect;
432    getSection(DRI, Sect);
433    Result = Sect->Address;
434  }
435  return object_error::success;
436}
437
438error_code MachOObjectFile::getSectionSize(DataRefImpl DRI,
439                                           uint64_t &Result) const {
440  if (is64BitLoadCommand(MachOObj, DRI)) {
441    InMemoryStruct<macho::Section64> Sect;
442    getSection64(DRI, Sect);
443    Result = Sect->Size;
444  } else {
445    InMemoryStruct<macho::Section> Sect;
446    getSection(DRI, Sect);
447    Result = Sect->Size;
448  }
449  return object_error::success;
450}
451
452error_code MachOObjectFile::getSectionContents(DataRefImpl DRI,
453                                               StringRef &Result) const {
454  if (is64BitLoadCommand(MachOObj, DRI)) {
455    InMemoryStruct<macho::Section64> Sect;
456    getSection64(DRI, Sect);
457    Result = MachOObj->getData(Sect->Offset, Sect->Size);
458  } else {
459    InMemoryStruct<macho::Section> Sect;
460    getSection(DRI, Sect);
461    Result = MachOObj->getData(Sect->Offset, Sect->Size);
462  }
463  return object_error::success;
464}
465
466error_code MachOObjectFile::getSectionAlignment(DataRefImpl DRI,
467                                                uint64_t &Result) const {
468  if (is64BitLoadCommand(MachOObj, DRI)) {
469    InMemoryStruct<macho::Section64> Sect;
470    getSection64(DRI, Sect);
471    Result = uint64_t(1) << Sect->Align;
472  } else {
473    InMemoryStruct<macho::Section> Sect;
474    getSection(DRI, Sect);
475    Result = uint64_t(1) << Sect->Align;
476  }
477  return object_error::success;
478}
479
480error_code MachOObjectFile::isSectionText(DataRefImpl DRI,
481                                          bool &Result) const {
482  if (is64BitLoadCommand(MachOObj, DRI)) {
483    InMemoryStruct<macho::Section64> Sect;
484    getSection64(DRI, Sect);
485    Result = !strcmp(Sect->Name, "__text");
486  } else {
487    InMemoryStruct<macho::Section> Sect;
488    getSection(DRI, Sect);
489    Result = !strcmp(Sect->Name, "__text");
490  }
491  return object_error::success;
492}
493
494error_code MachOObjectFile::isSectionData(DataRefImpl DRI,
495                                          bool &Result) const {
496  // FIXME: Unimplemented.
497  Result = false;
498  return object_error::success;
499}
500
501error_code MachOObjectFile::isSectionBSS(DataRefImpl DRI,
502                                         bool &Result) const {
503  // FIXME: Unimplemented.
504  Result = false;
505  return object_error::success;
506}
507
508error_code MachOObjectFile::sectionContainsSymbol(DataRefImpl Sec,
509                                                  DataRefImpl Symb,
510                                                  bool &Result) const {
511  SymbolRef::Type ST;
512  getSymbolType(Symb, ST);
513  if (ST == SymbolRef::ST_External) {
514    Result = false;
515    return object_error::success;
516  }
517
518  uint64_t SectBegin, SectEnd;
519  getSectionAddress(Sec, SectBegin);
520  getSectionSize(Sec, SectEnd);
521  SectEnd += SectBegin;
522
523  if (MachOObj->is64Bit()) {
524    InMemoryStruct<macho::Symbol64TableEntry> Entry;
525    getSymbol64TableEntry(Symb, Entry);
526    uint64_t SymAddr= Entry->Value;
527    Result = (SymAddr >= SectBegin) && (SymAddr < SectEnd);
528  } else {
529    InMemoryStruct<macho::SymbolTableEntry> Entry;
530    getSymbolTableEntry(Symb, Entry);
531    uint64_t SymAddr= Entry->Value;
532    Result = (SymAddr >= SectBegin) && (SymAddr < SectEnd);
533  }
534
535  return object_error::success;
536}
537
538relocation_iterator MachOObjectFile::getSectionRelBegin(DataRefImpl Sec) const {
539  DataRefImpl ret;
540  ret.d.a = 0;
541  ret.d.b = getSectionIndex(Sec);
542  return relocation_iterator(RelocationRef(ret, this));
543}
544relocation_iterator MachOObjectFile::getSectionRelEnd(DataRefImpl Sec) const {
545  uint32_t last_reloc;
546  if (is64BitLoadCommand(MachOObj, Sec)) {
547    InMemoryStruct<macho::Section64> Sect;
548    getSection64(Sec, Sect);
549    last_reloc = Sect->NumRelocationTableEntries;
550  } else {
551    InMemoryStruct<macho::Section> Sect;
552    getSection(Sec, Sect);
553    last_reloc = Sect->NumRelocationTableEntries;
554  }
555  DataRefImpl ret;
556  ret.d.a = last_reloc;
557  ret.d.b = getSectionIndex(Sec);
558  return relocation_iterator(RelocationRef(ret, this));
559}
560
561section_iterator MachOObjectFile::begin_sections() const {
562  DataRefImpl DRI;
563  DRI.d.a = DRI.d.b = 0;
564  moveToNextSection(DRI);
565  return section_iterator(SectionRef(DRI, this));
566}
567
568section_iterator MachOObjectFile::end_sections() const {
569  DataRefImpl DRI;
570  DRI.d.a = MachOObj->getHeader().NumLoadCommands;
571  DRI.d.b = 0;
572  return section_iterator(SectionRef(DRI, this));
573}
574
575/*===-- Relocations -------------------------------------------------------===*/
576
577void MachOObjectFile::
578getRelocation(DataRefImpl Rel,
579              InMemoryStruct<macho::RelocationEntry> &Res) const {
580  uint32_t relOffset;
581  if (MachOObj->is64Bit()) {
582    InMemoryStruct<macho::Section64> Sect;
583    getSection64(Sections[Rel.d.b], Sect);
584    relOffset = Sect->RelocationTableOffset;
585  } else {
586    InMemoryStruct<macho::Section> Sect;
587    getSection(Sections[Rel.d.b], Sect);
588    relOffset = Sect->RelocationTableOffset;
589  }
590  MachOObj->ReadRelocationEntry(relOffset, Rel.d.a, Res);
591}
592error_code MachOObjectFile::getRelocationNext(DataRefImpl Rel,
593                                              RelocationRef &Res) const {
594  ++Rel.d.a;
595  Res = RelocationRef(Rel, this);
596  return object_error::success;
597}
598error_code MachOObjectFile::getRelocationAddress(DataRefImpl Rel,
599                                                 uint64_t &Res) const {
600  const uint8_t* sectAddress = 0;
601  if (MachOObj->is64Bit()) {
602    InMemoryStruct<macho::Section64> Sect;
603    getSection64(Sections[Rel.d.b], Sect);
604    sectAddress += Sect->Address;
605  } else {
606    InMemoryStruct<macho::Section> Sect;
607    getSection(Sections[Rel.d.b], Sect);
608    sectAddress += Sect->Address;
609  }
610  InMemoryStruct<macho::RelocationEntry> RE;
611  getRelocation(Rel, RE);
612
613  unsigned Arch = getArch();
614  bool isScattered = (Arch != Triple::x86_64) &&
615                     (RE->Word0 & macho::RF_Scattered);
616  uint64_t RelAddr = 0;
617  if (isScattered)
618    RelAddr = RE->Word0 & 0xFFFFFF;
619  else
620    RelAddr = RE->Word0;
621
622  Res = reinterpret_cast<uintptr_t>(sectAddress + RelAddr);
623  return object_error::success;
624}
625error_code MachOObjectFile::getRelocationSymbol(DataRefImpl Rel,
626                                                SymbolRef &Res) const {
627  InMemoryStruct<macho::RelocationEntry> RE;
628  getRelocation(Rel, RE);
629  uint32_t SymbolIdx = RE->Word1 & 0xffffff;
630  bool isExtern = (RE->Word1 >> 27) & 1;
631
632  DataRefImpl Sym;
633  Sym.d.a = Sym.d.b = 0;
634  moveToNextSymbol(Sym);
635  if (isExtern) {
636    for (unsigned i = 0; i < SymbolIdx; i++) {
637      Sym.d.b++;
638      moveToNextSymbol(Sym);
639      assert(Sym.d.a < MachOObj->getHeader().NumLoadCommands &&
640             "Relocation symbol index out of range!");
641    }
642  }
643  Res = SymbolRef(Sym, this);
644  return object_error::success;
645}
646error_code MachOObjectFile::getRelocationType(DataRefImpl Rel,
647                                              uint64_t &Res) const {
648  InMemoryStruct<macho::RelocationEntry> RE;
649  getRelocation(Rel, RE);
650  Res = RE->Word0;
651  Res <<= 32;
652  Res |= RE->Word1;
653  return object_error::success;
654}
655error_code MachOObjectFile::getRelocationTypeName(DataRefImpl Rel,
656                                          SmallVectorImpl<char> &Result) const {
657  // TODO: Support scattered relocations.
658  StringRef res;
659  InMemoryStruct<macho::RelocationEntry> RE;
660  getRelocation(Rel, RE);
661
662  unsigned Arch = getArch();
663  bool isScattered = (Arch != Triple::x86_64) &&
664                     (RE->Word0 & macho::RF_Scattered);
665
666  unsigned r_type;
667  if (isScattered)
668    r_type = (RE->Word0 >> 24) & 0xF;
669  else
670    r_type = (RE->Word1 >> 28) & 0xF;
671
672  switch (Arch) {
673    case Triple::x86: {
674      const char* Table[] =  {
675        "GENERIC_RELOC_VANILLA",
676        "GENERIC_RELOC_PAIR",
677        "GENERIC_RELOC_SECTDIFF",
678        "GENERIC_RELOC_PB_LA_PTR",
679        "GENERIC_RELOC_LOCAL_SECTDIFF",
680        "GENERIC_RELOC_TLV" };
681
682      if (r_type > 6)
683        res = "Unknown";
684      else
685        res = Table[r_type];
686      break;
687    }
688    case Triple::x86_64: {
689      const char* Table[] =  {
690        "X86_64_RELOC_UNSIGNED",
691        "X86_64_RELOC_SIGNED",
692        "X86_64_RELOC_BRANCH",
693        "X86_64_RELOC_GOT_LOAD",
694        "X86_64_RELOC_GOT",
695        "X86_64_RELOC_SUBTRACTOR",
696        "X86_64_RELOC_SIGNED_1",
697        "X86_64_RELOC_SIGNED_2",
698        "X86_64_RELOC_SIGNED_4",
699        "X86_64_RELOC_TLV" };
700
701      if (r_type > 9)
702        res = "Unknown";
703      else
704        res = Table[r_type];
705      break;
706    }
707    case Triple::arm: {
708      const char* Table[] =  {
709        "ARM_RELOC_VANILLA",
710        "ARM_RELOC_PAIR",
711        "ARM_RELOC_SECTDIFF",
712        "ARM_RELOC_LOCAL_SECTDIFF",
713        "ARM_RELOC_PB_LA_PTR",
714        "ARM_RELOC_BR24",
715        "ARM_THUMB_RELOC_BR22",
716        "ARM_THUMB_32BIT_BRANCH",
717        "ARM_RELOC_HALF",
718        "ARM_RELOC_HALF_SECTDIFF" };
719
720      if (r_type > 9)
721        res = "Unknown";
722      else
723        res = Table[r_type];
724      break;
725    }
726    case Triple::ppc: {
727      const char* Table[] =  {
728        "PPC_RELOC_VANILLA",
729        "PPC_RELOC_PAIR",
730        "PPC_RELOC_BR14",
731        "PPC_RELOC_BR24",
732        "PPC_RELOC_HI16",
733        "PPC_RELOC_LO16",
734        "PPC_RELOC_HA16",
735        "PPC_RELOC_LO14",
736        "PPC_RELOC_SECTDIFF",
737        "PPC_RELOC_PB_LA_PTR",
738        "PPC_RELOC_HI16_SECTDIFF",
739        "PPC_RELOC_LO16_SECTDIFF",
740        "PPC_RELOC_HA16_SECTDIFF",
741        "PPC_RELOC_JBSR",
742        "PPC_RELOC_LO14_SECTDIFF",
743        "PPC_RELOC_LOCAL_SECTDIFF" };
744
745      res = Table[r_type];
746      break;
747    }
748    case Triple::UnknownArch:
749      res = "Unknown";
750      break;
751  }
752  Result.append(res.begin(), res.end());
753  return object_error::success;
754}
755error_code MachOObjectFile::getRelocationAdditionalInfo(DataRefImpl Rel,
756                                                        int64_t &Res) const {
757  InMemoryStruct<macho::RelocationEntry> RE;
758  getRelocation(Rel, RE);
759  bool isExtern = (RE->Word1 >> 27) & 1;
760  Res = 0;
761  if (!isExtern) {
762    const uint8_t* sectAddress = base();
763    if (MachOObj->is64Bit()) {
764      InMemoryStruct<macho::Section64> Sect;
765      getSection64(Sections[Rel.d.b], Sect);
766      sectAddress += Sect->Offset;
767    } else {
768      InMemoryStruct<macho::Section> Sect;
769      getSection(Sections[Rel.d.b], Sect);
770      sectAddress += Sect->Offset;
771    }
772    Res = reinterpret_cast<uintptr_t>(sectAddress);
773  }
774  return object_error::success;
775}
776
777// Helper to advance a section or symbol iterator multiple increments at a time.
778template<class T>
779error_code advance(T &it, size_t Val) {
780  error_code ec;
781  while (Val--) {
782    it.increment(ec);
783  }
784  return ec;
785}
786
787template<class T>
788void advanceTo(T &it, size_t Val) {
789  if (error_code ec = advance(it, Val))
790    report_fatal_error(ec.message());
791}
792
793void MachOObjectFile::printRelocationTargetName(
794                                     InMemoryStruct<macho::RelocationEntry>& RE,
795                                     raw_string_ostream &fmt) const {
796  unsigned Arch = getArch();
797  bool isScattered = (Arch != Triple::x86_64) &&
798                     (RE->Word0 & macho::RF_Scattered);
799
800  // Target of a scattered relocation is an address.  In the interest of
801  // generating pretty output, scan through the symbol table looking for a
802  // symbol that aligns with that address.  If we find one, print it.
803  // Otherwise, we just print the hex address of the target.
804  if (isScattered) {
805    uint32_t Val = RE->Word1;
806
807    error_code ec;
808    for (symbol_iterator SI = begin_symbols(), SE = end_symbols(); SI != SE;
809        SI.increment(ec)) {
810      if (ec) report_fatal_error(ec.message());
811
812      uint64_t Addr;
813      StringRef Name;
814
815      if ((ec = SI->getAddress(Addr)))
816        report_fatal_error(ec.message());
817      if (Addr != Val) continue;
818      if ((ec = SI->getName(Name)))
819        report_fatal_error(ec.message());
820      fmt << Name;
821      return;
822    }
823
824    // If we couldn't find a symbol that this relocation refers to, try
825    // to find a section beginning instead.
826    for (section_iterator SI = begin_sections(), SE = end_sections(); SI != SE;
827         SI.increment(ec)) {
828      if (ec) report_fatal_error(ec.message());
829
830      uint64_t Addr;
831      StringRef Name;
832
833      if ((ec = SI->getAddress(Addr)))
834        report_fatal_error(ec.message());
835      if (Addr != Val) continue;
836      if ((ec = SI->getName(Name)))
837        report_fatal_error(ec.message());
838      fmt << Name;
839      return;
840    }
841
842    fmt << format("0x%x", Val);
843    return;
844  }
845
846  StringRef S;
847  bool isExtern = (RE->Word1 >> 27) & 1;
848  uint32_t Val = RE->Word1 & 0xFFFFFF;
849
850  if (isExtern) {
851    symbol_iterator SI = begin_symbols();
852    advanceTo(SI, Val);
853    SI->getName(S);
854  } else {
855    section_iterator SI = begin_sections();
856    advanceTo(SI, Val);
857    SI->getName(S);
858  }
859
860  fmt << S;
861}
862
863error_code MachOObjectFile::getRelocationValueString(DataRefImpl Rel,
864                                          SmallVectorImpl<char> &Result) const {
865  InMemoryStruct<macho::RelocationEntry> RE;
866  getRelocation(Rel, RE);
867
868  unsigned Arch = getArch();
869  bool isScattered = (Arch != Triple::x86_64) &&
870                     (RE->Word0 & macho::RF_Scattered);
871
872  std::string fmtbuf;
873  raw_string_ostream fmt(fmtbuf);
874
875  unsigned Type;
876  if (isScattered)
877    Type = (RE->Word0 >> 24) & 0xF;
878  else
879    Type = (RE->Word1 >> 28) & 0xF;
880
881  bool isPCRel;
882  if (isScattered)
883    isPCRel = ((RE->Word0 >> 30) & 1);
884  else
885    isPCRel = ((RE->Word1 >> 24) & 1);
886
887  // Determine any addends that should be displayed with the relocation.
888  // These require decoding the relocation type, which is triple-specific.
889
890  // X86_64 has entirely custom relocation types.
891  if (Arch == Triple::x86_64) {
892    bool isPCRel = ((RE->Word1 >> 24) & 1);
893
894    switch (Type) {
895      case macho::RIT_X86_64_GOTLoad:   // X86_64_RELOC_GOT_LOAD
896      case macho::RIT_X86_64_GOT: {     // X86_64_RELOC_GOT
897        printRelocationTargetName(RE, fmt);
898        fmt << "@GOT";
899        if (isPCRel) fmt << "PCREL";
900        break;
901      }
902      case macho::RIT_X86_64_Subtractor: { // X86_64_RELOC_SUBTRACTOR
903        InMemoryStruct<macho::RelocationEntry> RENext;
904        DataRefImpl RelNext = Rel;
905        RelNext.d.a++;
906        getRelocation(RelNext, RENext);
907
908        // X86_64_SUBTRACTOR must be followed by a relocation of type
909        // X86_64_RELOC_UNSIGNED.
910        // NOTE: Scattered relocations don't exist on x86_64.
911        unsigned RType = (RENext->Word1 >> 28) & 0xF;
912        if (RType != 0)
913          report_fatal_error("Expected X86_64_RELOC_UNSIGNED after "
914                             "X86_64_RELOC_SUBTRACTOR.");
915
916        // The X86_64_RELOC_UNSIGNED contains the minuend symbol,
917        // X86_64_SUBTRACTOR contains to the subtrahend.
918        printRelocationTargetName(RENext, fmt);
919        fmt << "-";
920        printRelocationTargetName(RE, fmt);
921      }
922      case macho::RIT_X86_64_TLV:
923        printRelocationTargetName(RE, fmt);
924        fmt << "@TLV";
925        if (isPCRel) fmt << "P";
926        break;
927      case macho::RIT_X86_64_Signed1: // X86_64_RELOC_SIGNED1
928        printRelocationTargetName(RE, fmt);
929        fmt << "-1";
930        break;
931      case macho::RIT_X86_64_Signed2: // X86_64_RELOC_SIGNED2
932        printRelocationTargetName(RE, fmt);
933        fmt << "-2";
934        break;
935      case macho::RIT_X86_64_Signed4: // X86_64_RELOC_SIGNED4
936        printRelocationTargetName(RE, fmt);
937        fmt << "-4";
938        break;
939      default:
940        printRelocationTargetName(RE, fmt);
941        break;
942    }
943  // X86 and ARM share some relocation types in common.
944  } else if (Arch == Triple::x86 || Arch == Triple::arm) {
945    // Generic relocation types...
946    switch (Type) {
947      case macho::RIT_Pair: // GENERIC_RELOC_PAIR - prints no info
948        return object_error::success;
949      case macho::RIT_Difference: { // GENERIC_RELOC_SECTDIFF
950        InMemoryStruct<macho::RelocationEntry> RENext;
951        DataRefImpl RelNext = Rel;
952        RelNext.d.a++;
953        getRelocation(RelNext, RENext);
954
955        // X86 sect diff's must be followed by a relocation of type
956        // GENERIC_RELOC_PAIR.
957        bool isNextScattered = (Arch != Triple::x86_64) &&
958                               (RENext->Word0 & macho::RF_Scattered);
959        unsigned RType;
960        if (isNextScattered)
961          RType = (RENext->Word0 >> 24) & 0xF;
962        else
963          RType = (RENext->Word1 >> 28) & 0xF;
964        if (RType != 1)
965          report_fatal_error("Expected GENERIC_RELOC_PAIR after "
966                             "GENERIC_RELOC_SECTDIFF.");
967
968        printRelocationTargetName(RE, fmt);
969        fmt << "-";
970        printRelocationTargetName(RENext, fmt);
971        break;
972      }
973    }
974
975    if (Arch == Triple::x86) {
976      // All X86 relocations that need special printing were already
977      // handled in the generic code.
978      switch (Type) {
979        case macho::RIT_Generic_LocalDifference:{// GENERIC_RELOC_LOCAL_SECTDIFF
980          InMemoryStruct<macho::RelocationEntry> RENext;
981          DataRefImpl RelNext = Rel;
982          RelNext.d.a++;
983          getRelocation(RelNext, RENext);
984
985          // X86 sect diff's must be followed by a relocation of type
986          // GENERIC_RELOC_PAIR.
987          bool isNextScattered = (Arch != Triple::x86_64) &&
988                               (RENext->Word0 & macho::RF_Scattered);
989          unsigned RType;
990          if (isNextScattered)
991            RType = (RENext->Word0 >> 24) & 0xF;
992          else
993            RType = (RENext->Word1 >> 28) & 0xF;
994          if (RType != 1)
995            report_fatal_error("Expected GENERIC_RELOC_PAIR after "
996                               "GENERIC_RELOC_LOCAL_SECTDIFF.");
997
998          printRelocationTargetName(RE, fmt);
999          fmt << "-";
1000          printRelocationTargetName(RENext, fmt);
1001          break;
1002        }
1003        case macho::RIT_Generic_TLV: {
1004          printRelocationTargetName(RE, fmt);
1005          fmt << "@TLV";
1006          if (isPCRel) fmt << "P";
1007          break;
1008        }
1009        default:
1010          printRelocationTargetName(RE, fmt);
1011      }
1012    } else { // ARM-specific relocations
1013      switch (Type) {
1014        case macho::RIT_ARM_Half:             // ARM_RELOC_HALF
1015        case macho::RIT_ARM_HalfDifference: { // ARM_RELOC_HALF_SECTDIFF
1016          // Half relocations steal a bit from the length field to encode
1017          // whether this is an upper16 or a lower16 relocation.
1018          bool isUpper;
1019          if (isScattered)
1020            isUpper = (RE->Word0 >> 28) & 1;
1021          else
1022            isUpper = (RE->Word1 >> 25) & 1;
1023
1024          if (isUpper)
1025            fmt << ":upper16:(";
1026          else
1027            fmt << ":lower16:(";
1028          printRelocationTargetName(RE, fmt);
1029
1030          InMemoryStruct<macho::RelocationEntry> RENext;
1031          DataRefImpl RelNext = Rel;
1032          RelNext.d.a++;
1033          getRelocation(RelNext, RENext);
1034
1035          // ARM half relocs must be followed by a relocation of type
1036          // ARM_RELOC_PAIR.
1037          bool isNextScattered = (Arch != Triple::x86_64) &&
1038                                 (RENext->Word0 & macho::RF_Scattered);
1039          unsigned RType;
1040          if (isNextScattered)
1041            RType = (RENext->Word0 >> 24) & 0xF;
1042          else
1043            RType = (RENext->Word1 >> 28) & 0xF;
1044
1045          if (RType != 1)
1046            report_fatal_error("Expected ARM_RELOC_PAIR after "
1047                               "GENERIC_RELOC_HALF");
1048
1049          // NOTE: The half of the target virtual address is stashed in the
1050          // address field of the secondary relocation, but we can't reverse
1051          // engineer the constant offset from it without decoding the movw/movt
1052          // instruction to find the other half in its immediate field.
1053
1054          // ARM_RELOC_HALF_SECTDIFF encodes the second section in the
1055          // symbol/section pointer of the follow-on relocation.
1056          if (Type == macho::RIT_ARM_HalfDifference) {
1057            fmt << "-";
1058            printRelocationTargetName(RENext, fmt);
1059          }
1060
1061          fmt << ")";
1062          break;
1063        }
1064        default: {
1065          printRelocationTargetName(RE, fmt);
1066        }
1067      }
1068    }
1069  } else
1070    printRelocationTargetName(RE, fmt);
1071
1072  fmt.flush();
1073  Result.append(fmtbuf.begin(), fmtbuf.end());
1074  return object_error::success;
1075}
1076
1077error_code MachOObjectFile::getRelocationHidden(DataRefImpl Rel,
1078                                                bool &Result) const {
1079  InMemoryStruct<macho::RelocationEntry> RE;
1080  getRelocation(Rel, RE);
1081
1082  unsigned Arch = getArch();
1083  bool isScattered = (Arch != Triple::x86_64) &&
1084                     (RE->Word0 & macho::RF_Scattered);
1085  unsigned Type;
1086  if (isScattered)
1087    Type = (RE->Word0 >> 24) & 0xF;
1088  else
1089    Type = (RE->Word1 >> 28) & 0xF;
1090
1091  Result = false;
1092
1093  // On arches that use the generic relocations, GENERIC_RELOC_PAIR
1094  // is always hidden.
1095  if (Arch == Triple::x86 || Arch == Triple::arm) {
1096    if (Type == macho::RIT_Pair) Result = true;
1097  } else if (Arch == Triple::x86_64) {
1098    // On x86_64, X86_64_RELOC_UNSIGNED is hidden only when it follows
1099    // an X864_64_RELOC_SUBTRACTOR.
1100    if (Type == macho::RIT_X86_64_Unsigned && Rel.d.a > 0) {
1101      DataRefImpl RelPrev = Rel;
1102      RelPrev.d.a--;
1103      InMemoryStruct<macho::RelocationEntry> REPrev;
1104      getRelocation(RelPrev, REPrev);
1105
1106      unsigned PrevType = (REPrev->Word1 >> 28) & 0xF;
1107
1108      if (PrevType == macho::RIT_X86_64_Subtractor) Result = true;
1109    }
1110  }
1111
1112  return object_error::success;
1113}
1114
1115/*===-- Miscellaneous -----------------------------------------------------===*/
1116
1117uint8_t MachOObjectFile::getBytesInAddress() const {
1118  return MachOObj->is64Bit() ? 8 : 4;
1119}
1120
1121StringRef MachOObjectFile::getFileFormatName() const {
1122  if (!MachOObj->is64Bit()) {
1123    switch (MachOObj->getHeader().CPUType) {
1124    case llvm::MachO::CPUTypeI386:
1125      return "Mach-O 32-bit i386";
1126    case llvm::MachO::CPUTypeARM:
1127      return "Mach-O arm";
1128    case llvm::MachO::CPUTypePowerPC:
1129      return "Mach-O 32-bit ppc";
1130    default:
1131      assert((MachOObj->getHeader().CPUType & llvm::MachO::CPUArchABI64) == 0 &&
1132             "64-bit object file when we're not 64-bit?");
1133      return "Mach-O 32-bit unknown";
1134    }
1135  }
1136
1137  switch (MachOObj->getHeader().CPUType) {
1138  case llvm::MachO::CPUTypeX86_64:
1139    return "Mach-O 64-bit x86-64";
1140  case llvm::MachO::CPUTypePowerPC64:
1141    return "Mach-O 64-bit ppc64";
1142  default:
1143    assert((MachOObj->getHeader().CPUType & llvm::MachO::CPUArchABI64) == 1 &&
1144           "32-bit object file when we're 64-bit?");
1145    return "Mach-O 64-bit unknown";
1146  }
1147}
1148
1149unsigned MachOObjectFile::getArch() const {
1150  switch (MachOObj->getHeader().CPUType) {
1151  case llvm::MachO::CPUTypeI386:
1152    return Triple::x86;
1153  case llvm::MachO::CPUTypeX86_64:
1154    return Triple::x86_64;
1155  case llvm::MachO::CPUTypeARM:
1156    return Triple::arm;
1157  case llvm::MachO::CPUTypePowerPC:
1158    return Triple::ppc;
1159  case llvm::MachO::CPUTypePowerPC64:
1160    return Triple::ppc64;
1161  default:
1162    return Triple::UnknownArch;
1163  }
1164}
1165
1166} // end namespace object
1167} // end namespace llvm
1168