MachOUniversal.cpp revision 261991
1142871Strhodes//===- MachOUniversal.cpp - Mach-O universal binary -------------*- C++ -*-===//
2142871Strhodes//
3142871Strhodes//                     The LLVM Compiler Infrastructure
4142871Strhodes//
5142871Strhodes// This file is distributed under the University of Illinois Open Source
6142871Strhodes// License. See LICENSE.TXT for details.
7142871Strhodes//
8142871Strhodes//===----------------------------------------------------------------------===//
9142871Strhodes//
10142871Strhodes// This file defines the MachOUniversalBinary class.
11142871Strhodes//
12142871Strhodes//===----------------------------------------------------------------------===//
13142871Strhodes
14142871Strhodes#include "llvm/Object/MachOUniversal.h"
15142871Strhodes
16142871Strhodes#include "llvm/Object/MachO.h"
17142871Strhodes#include "llvm/Object/ObjectFile.h"
18142871Strhodes#include "llvm/Support/Casting.h"
19142871Strhodes#include "llvm/Support/Host.h"
20142871Strhodes#include "llvm/Support/MemoryBuffer.h"
21142871Strhodes
22142871Strhodesusing namespace llvm;
23142871Strhodesusing namespace object;
24142871Strhodes
25142871Strhodestemplate<typename T>
26142871Strhodesstatic void SwapValue(T &Value) {
27142871Strhodes  Value = sys::SwapByteOrder(Value);
28142871Strhodes}
29142871Strhodes
30142871Strhodestemplate<typename T>
31142871Strhodesstatic void SwapStruct(T &Value);
32142871Strhodes
33142871Strhodestemplate<>
34142871Strhodesvoid SwapStruct(MachO::fat_header &H) {
35142871Strhodes  SwapValue(H.magic);
36142871Strhodes  SwapValue(H.nfat_arch);
37142871Strhodes}
38142871Strhodes
39142871Strhodestemplate<>
40142871Strhodesvoid SwapStruct(MachO::fat_arch &H) {
41142871Strhodes  SwapValue(H.cputype);
42142871Strhodes  SwapValue(H.cpusubtype);
43142871Strhodes  SwapValue(H.offset);
44142871Strhodes  SwapValue(H.size);
45142871Strhodes  SwapValue(H.align);
46142871Strhodes}
47142871Strhodes
48142871Strhodestemplate<typename T>
49142871Strhodesstatic T getUniversalBinaryStruct(const char *Ptr) {
50142871Strhodes  T Res;
51142871Strhodes  memcpy(&Res, Ptr, sizeof(T));
52142871Strhodes  // Universal binary headers have big-endian byte order.
53142871Strhodes  if (sys::IsLittleEndianHost)
54142871Strhodes    SwapStruct(Res);
55142871Strhodes  return Res;
56142871Strhodes}
57142871Strhodes
58142871StrhodesMachOUniversalBinary::ObjectForArch::ObjectForArch(
59142871Strhodes    const MachOUniversalBinary *Parent, uint32_t Index)
60142871Strhodes    : Parent(Parent), Index(Index) {
61142871Strhodes  if (Parent == 0 || Index > Parent->getNumberOfObjects()) {
62142871Strhodes    clear();
63142871Strhodes  } else {
64142871Strhodes    // Parse object header.
65142871Strhodes    StringRef ParentData = Parent->getData();
66142871Strhodes    const char *HeaderPos = ParentData.begin() + sizeof(MachO::fat_header) +
67142871Strhodes                            Index * sizeof(MachO::fat_arch);
68142871Strhodes    Header = getUniversalBinaryStruct<MachO::fat_arch>(HeaderPos);
69142871Strhodes    if (ParentData.size() < Header.offset + Header.size) {
70142871Strhodes      clear();
71142871Strhodes    }
72142871Strhodes  }
73142871Strhodes}
74142871Strhodes
75142871Strhodeserror_code MachOUniversalBinary::ObjectForArch::getAsObjectFile(
76142871Strhodes    OwningPtr<ObjectFile> &Result) const {
77142871Strhodes  if (Parent) {
78142871Strhodes    StringRef ParentData = Parent->getData();
79142871Strhodes    StringRef ObjectData = ParentData.substr(Header.offset, Header.size);
80142871Strhodes    std::string ObjectName =
81142871Strhodes        Parent->getFileName().str() + ":" +
82142871Strhodes        Triple::getArchTypeName(MachOObjectFile::getArch(Header.cputype));
83142871Strhodes    MemoryBuffer *ObjBuffer = MemoryBuffer::getMemBuffer(
84142871Strhodes        ObjectData, ObjectName, false);
85142871Strhodes    if (ObjectFile *Obj = ObjectFile::createMachOObjectFile(ObjBuffer)) {
86142871Strhodes      Result.reset(Obj);
87142871Strhodes      return object_error::success;
88142871Strhodes    }
89142871Strhodes  }
90142871Strhodes  return object_error::parse_failed;
91142871Strhodes}
92142871Strhodes
93142871Strhodesvoid MachOUniversalBinary::anchor() { }
94142871Strhodes
95142871StrhodesMachOUniversalBinary::MachOUniversalBinary(MemoryBuffer *Source,
96142871Strhodes                                           error_code &ec)
97142871Strhodes  : Binary(Binary::ID_MachOUniversalBinary, Source),
98142871Strhodes    NumberOfObjects(0) {
99142871Strhodes  if (Source->getBufferSize() < sizeof(MachO::fat_header)) {
100142871Strhodes    ec = object_error::invalid_file_type;
101142871Strhodes    return;
102142871Strhodes  }
103142871Strhodes  // Check for magic value and sufficient header size.
104142871Strhodes  StringRef Buf = getData();
105142871Strhodes  MachO::fat_header H= getUniversalBinaryStruct<MachO::fat_header>(Buf.begin());
106142871Strhodes  NumberOfObjects = H.nfat_arch;
107142871Strhodes  uint32_t MinSize = sizeof(MachO::fat_header) +
108142871Strhodes                     sizeof(MachO::fat_arch) * NumberOfObjects;
109142871Strhodes  if (H.magic != MachO::FAT_MAGIC || Buf.size() < MinSize) {
110142871Strhodes    ec = object_error::parse_failed;
111142871Strhodes    return;
112142871Strhodes  }
113142871Strhodes  ec = object_error::success;
114142871Strhodes}
115142871Strhodes
116142871Strhodesstatic bool getCTMForArch(Triple::ArchType Arch, MachO::CPUType &CTM) {
117142871Strhodes  switch (Arch) {
118142871Strhodes    case Triple::x86:    CTM = MachO::CPU_TYPE_I386; return true;
119142871Strhodes    case Triple::x86_64: CTM = MachO::CPU_TYPE_X86_64; return true;
120142871Strhodes    case Triple::arm:    CTM = MachO::CPU_TYPE_ARM; return true;
121142871Strhodes    case Triple::sparc:  CTM = MachO::CPU_TYPE_SPARC; return true;
122142871Strhodes    case Triple::ppc:    CTM = MachO::CPU_TYPE_POWERPC; return true;
123142871Strhodes    case Triple::ppc64:  CTM = MachO::CPU_TYPE_POWERPC64; return true;
124142871Strhodes    default: return false;
125142871Strhodes  }
126142871Strhodes}
127142871Strhodes
128142871Strhodeserror_code
129142871StrhodesMachOUniversalBinary::getObjectForArch(Triple::ArchType Arch,
130142871Strhodes                                       OwningPtr<ObjectFile> &Result) const {
131142871Strhodes  MachO::CPUType CTM;
132142871Strhodes  if (!getCTMForArch(Arch, CTM))
133142871Strhodes    return object_error::arch_not_found;
134142871Strhodes  for (object_iterator I = begin_objects(), E = end_objects(); I != E; ++I) {
135142871Strhodes    if (I->getCPUType() == static_cast<uint32_t>(CTM))
136142871Strhodes      return I->getAsObjectFile(Result);
137142871Strhodes  }
138142871Strhodes  return object_error::arch_not_found;
139142871Strhodes}
140142871Strhodes