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