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