MachOObjectFile.cpp revision d8fa76d4bed067cd8662c3196211bc90cc8d4470
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/MemoryBuffer.h"
19#include "llvm/Support/raw_ostream.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  Res = reinterpret_cast<uintptr_t>(sectAddress + RE->Word0);
613  return object_error::success;
614}
615error_code MachOObjectFile::getRelocationSymbol(DataRefImpl Rel,
616                                                SymbolRef &Res) const {
617  InMemoryStruct<macho::RelocationEntry> RE;
618  getRelocation(Rel, RE);
619  uint32_t SymbolIdx = RE->Word1 & 0xffffff;
620  bool isExtern = (RE->Word1 >> 27) & 1;
621
622  DataRefImpl Sym;
623  Sym.d.a = Sym.d.b = 0;
624  moveToNextSymbol(Sym);
625  if (isExtern) {
626    for (unsigned i = 0; i < SymbolIdx; i++) {
627      Sym.d.b++;
628      moveToNextSymbol(Sym);
629      assert(Sym.d.a < MachOObj->getHeader().NumLoadCommands &&
630             "Relocation symbol index out of range!");
631    }
632  }
633  Res = SymbolRef(Sym, this);
634  return object_error::success;
635}
636error_code MachOObjectFile::getRelocationType(DataRefImpl Rel,
637                                              uint32_t &Res) const {
638  InMemoryStruct<macho::RelocationEntry> RE;
639  getRelocation(Rel, RE);
640  Res = RE->Word1;
641  return object_error::success;
642}
643error_code MachOObjectFile::getRelocationTypeName(DataRefImpl Rel,
644                                          SmallVectorImpl<char> &Result) const {
645  // TODO: Support scattered relocations.
646  StringRef res;
647  InMemoryStruct<macho::RelocationEntry> RE;
648  getRelocation(Rel, RE);
649  unsigned r_type = (RE->Word1 >> 28) & 0xF;
650
651  unsigned Arch = getArch();
652  switch (Arch) {
653    case Triple::x86: {
654      const char* Table[] =  {
655        "GENERIC_RELOC_VANILLA",
656        "GENERIC_RELOC_PAIR",
657        "GENERIC_RELOC_SECTDIFF",
658        "GENERIC_RELOC_LOCAL_SECTDIFF",
659        "GENERIC_RELOC_PB_LA_PTR" };
660
661      if (r_type > 4)
662        res = "Unknown";
663      else
664        res = Table[r_type];
665      break;
666    }
667    case Triple::x86_64: {
668      const char* Table[] =  {
669        "X86_64_RELOC_UNSIGNED",
670        "X86_64_RELOC_SIGNED",
671        "X86_64_RELOC_BRANCH",
672        "X86_64_RELOC_GOT_LOAD",
673        "X86_64_RELOC_GOT",
674        "X86_64_RELOC_SUBTRACTOR",
675        "X86_64_RELOC_SIGNED_1",
676        "X86_64_RELOC_SIGNED_2",
677        "X86_64_RELOC_SIGNED_4",
678        "X86_64_RELOC_TLV" };
679
680      if (r_type > 9)
681        res = "Unknown";
682      else
683        res = Table[r_type];
684      break;
685    }
686    case Triple::arm: {
687      const char* Table[] =  {
688        "ARM_RELOC_VANILLA",
689        "ARM_RELOC_PAIR",
690        "ARM_RELOC_SECTDIFF",
691        "ARM_RELOC_LOCAL_SECTDIFF",
692        "ARM_RELOC_PB_LA_PTR",
693        "ARM_RELOC_BR24",
694        "ARM_THUMB_RELOC_BR22",
695        "ARM_THUMB_32BIT_BRANCH",
696        "ARM_RELOC_HALF",
697        "ARM_RELOC_HALF_SECTDIFF" };
698
699      if (r_type > 9)
700        res = "Unknown";
701      else
702        res = Table[r_type];
703      break;
704    }
705    case Triple::ppc: {
706      const char* Table[] =  {
707        "PPC_RELOC_VANILLA",
708        "PPC_RELOC_PAIR",
709        "PPC_RELOC_BR14",
710        "PPC_RELOC_BR24",
711        "PPC_RELOC_HI16",
712        "PPC_RELOC_LO16",
713        "PPC_RELOC_HA16",
714        "PPC_RELOC_LO14",
715        "PPC_RELOC_SECTDIFF",
716        "PPC_RELOC_PB_LA_PTR",
717        "PPC_RELOC_HI16_SECTDIFF",
718        "PPC_RELOC_LO16_SECTDIFF",
719        "PPC_RELOC_HA16_SECTDIFF",
720        "PPC_RELOC_JBSR",
721        "PPC_RELOC_LO14_SECTDIFF",
722        "PPC_RELOC_LOCAL_SECTDIFF" };
723
724      res = Table[r_type];
725      break;
726    }
727    case Triple::UnknownArch:
728      res = "Unknown";
729      break;
730  }
731  Result.append(res.begin(), res.end());
732  return object_error::success;
733}
734error_code MachOObjectFile::getRelocationAdditionalInfo(DataRefImpl Rel,
735                                                        int64_t &Res) const {
736  InMemoryStruct<macho::RelocationEntry> RE;
737  getRelocation(Rel, RE);
738  bool isExtern = (RE->Word1 >> 27) & 1;
739  Res = 0;
740  if (!isExtern) {
741    const uint8_t* sectAddress = base();
742    if (MachOObj->is64Bit()) {
743      InMemoryStruct<macho::Section64> Sect;
744      getSection64(Sections[Rel.d.b], Sect);
745      sectAddress += Sect->Offset;
746    } else {
747      InMemoryStruct<macho::Section> Sect;
748      getSection(Sections[Rel.d.b], Sect);
749      sectAddress += Sect->Offset;
750    }
751    Res = reinterpret_cast<uintptr_t>(sectAddress);
752  }
753  return object_error::success;
754}
755
756// Helper to advance a section or symbol iterator multiple increments at a time.
757template<class T>
758error_code advance(T &it, size_t Val) {
759  error_code ec;
760  while (Val--) {
761    it.increment(ec);
762  }
763  return ec;
764}
765
766template<class T>
767void advanceTo(T &it, size_t Val) {
768  if (error_code ec = advance(it, Val))
769    report_fatal_error(ec.message());
770}
771
772error_code
773MachOObjectFile::getRelocationTargetName(uint32_t Idx, StringRef &S) const {
774  bool isExtern = (Idx >> 27) & 1;
775  uint32_t Val = Idx & 0xFFFFFF;
776  error_code ec;
777
778  if (isExtern) {
779    symbol_iterator SI = begin_symbols();
780    advanceTo(SI, Val);
781    ec = SI->getName(S);
782  } else {
783    section_iterator SI = begin_sections();
784    advanceTo(SI, Val);
785    ec = SI->getName(S);
786  }
787
788  return ec;
789}
790
791error_code MachOObjectFile::getRelocationValueString(DataRefImpl Rel,
792                                          SmallVectorImpl<char> &Result) const {
793  InMemoryStruct<macho::RelocationEntry> RE;
794  getRelocation(Rel, RE);
795
796  std::string addend;
797  raw_string_ostream addend_fmt(addend);
798
799  bool isPCRel = (RE->Word1 >> 25) & 1;
800  unsigned Type = (RE->Word1 >> 28) & 0xF;
801
802  // Determine any addends that should be displayed with the relocation.
803  // These require decoding the relocation type, which is triple-specific.
804  unsigned Arch = getArch();
805
806  // X86_64 has entirely custom relocation types.
807  if (Arch == Triple::x86_64) {
808    switch (Type) {
809      case 5: { // X86_64_RELOC_SUBTRACTOR
810        RelocationRef NextReloc;
811        if (error_code ec = getRelocationNext(Rel, NextReloc))
812          report_fatal_error(ec.message());
813
814        uint32_t SucessorType;
815        if (error_code ec = NextReloc.getType(SucessorType))
816          report_fatal_error(ec.message());
817
818        // X86_64_SUBTRACTOR must be followed by a relocation of type
819        // X86_64_RELOC_UNSIGNED.
820        unsigned RType = (SucessorType >> 28) & 0xF;
821        if (RType != 0)
822          report_fatal_error("Expected X86_64_RELOC_UNSIGNED after "
823                             "X86_64_RELOC_SUBTRACTOR.");
824
825        StringRef Name;
826        if (error_code ec = getRelocationTargetName(SucessorType, Name))
827          report_fatal_error(ec.message());
828
829        addend_fmt << "-" << Name;
830      }
831      case 6: // X86_64_RELOC_SIGNED1
832        addend_fmt << "-1";
833        break;
834      case 7: // X86_64_RELOC_SIGNED2
835        addend_fmt << "-2";
836        break;
837      case 8: // X86_64_RELOC_SIGNED4
838        addend_fmt << "-4";
839        break;
840    }
841  }
842
843  // X86 and ARM share some relocation types in common.
844  if (Arch == Triple::x86 || Arch == Triple::arm) {
845    switch (Type) {
846      case 1: // GENERIC_RELOC_PAIR - prints no info
847        return object_error::success;
848      case 2:   // GENERIC_RELOC_SECTDIFF
849      case 4: { // GENERIC_RELOC_LOCAL_SECTDIFF
850        RelocationRef NextReloc;
851        if (error_code ec = getRelocationNext(Rel, NextReloc))
852          report_fatal_error(ec.message());
853
854        uint32_t SucessorType;
855        if (error_code ec = NextReloc.getType(SucessorType))
856          report_fatal_error(ec.message());
857
858        // X86 sect diff's must be followed by a relocation of type
859        // GENERIC_RELOC_PAIR.
860        unsigned RType = (SucessorType >> 28) & 0xF;
861        if (RType != 1)
862          report_fatal_error("Expected GENERIC_RELOC_PAIR after "
863                             "GENERIC_RELOC_SECTDIFF or "
864                             "GENERIC_RELOC_LOCAL_SECTDIFF.");
865
866        StringRef Name;
867        if (error_code ec = getRelocationTargetName(SucessorType, Name))
868          report_fatal_error(ec.message());
869
870        addend_fmt << "-" << Name;
871
872      }
873    }
874  }
875
876  addend_fmt.flush();
877
878  std::string fmtbuf;
879  raw_string_ostream fmt(fmtbuf);
880
881  StringRef Name;
882  if (error_code ec = getRelocationTargetName(RE->Word1, Name))
883    report_fatal_error(ec.message());
884
885  fmt << Name << addend;
886  if (isPCRel) fmt << "-P";
887
888  fmt.flush();
889  Result.append(fmtbuf.begin(), fmtbuf.end());
890  return object_error::success;
891}
892
893/*===-- Miscellaneous -----------------------------------------------------===*/
894
895uint8_t MachOObjectFile::getBytesInAddress() const {
896  return MachOObj->is64Bit() ? 8 : 4;
897}
898
899StringRef MachOObjectFile::getFileFormatName() const {
900  if (!MachOObj->is64Bit()) {
901    switch (MachOObj->getHeader().CPUType) {
902    case llvm::MachO::CPUTypeI386:
903      return "Mach-O 32-bit i386";
904    case llvm::MachO::CPUTypeARM:
905      return "Mach-O arm";
906    case llvm::MachO::CPUTypePowerPC:
907      return "Mach-O 32-bit ppc";
908    default:
909      assert((MachOObj->getHeader().CPUType & llvm::MachO::CPUArchABI64) == 0 &&
910             "64-bit object file when we're not 64-bit?");
911      return "Mach-O 32-bit unknown";
912    }
913  }
914
915  switch (MachOObj->getHeader().CPUType) {
916  case llvm::MachO::CPUTypeX86_64:
917    return "Mach-O 64-bit x86-64";
918  case llvm::MachO::CPUTypePowerPC64:
919    return "Mach-O 64-bit ppc64";
920  default:
921    assert((MachOObj->getHeader().CPUType & llvm::MachO::CPUArchABI64) == 1 &&
922           "32-bit object file when we're 64-bit?");
923    return "Mach-O 64-bit unknown";
924  }
925}
926
927unsigned MachOObjectFile::getArch() const {
928  switch (MachOObj->getHeader().CPUType) {
929  case llvm::MachO::CPUTypeI386:
930    return Triple::x86;
931  case llvm::MachO::CPUTypeX86_64:
932    return Triple::x86_64;
933  case llvm::MachO::CPUTypeARM:
934    return Triple::arm;
935  case llvm::MachO::CPUTypePowerPC:
936    return Triple::ppc;
937  case llvm::MachO::CPUTypePowerPC64:
938    return Triple::ppc64;
939  default:
940    return Triple::UnknownArch;
941  }
942}
943
944} // end namespace object
945} // end namespace llvm
946