blob: b3b0c251c1005934227eb2147f39946ff852cd62 [file] [log] [blame]
Alexey Samsonove6388e62013-06-18 15:03:28 +00001//===- MachOUniversal.cpp - Mach-O universal binary -------------*- 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 MachOUniversalBinary class.
11//
12//===----------------------------------------------------------------------===//
13
14#include "llvm/Object/MachOUniversal.h"
Chandler Carruthd9903882015-01-14 11:23:27 +000015#include "llvm/Object/Archive.h"
Alexey Samsonove6388e62013-06-18 15:03:28 +000016#include "llvm/Object/MachO.h"
17#include "llvm/Object/ObjectFile.h"
18#include "llvm/Support/Casting.h"
19#include "llvm/Support/Host.h"
20#include "llvm/Support/MemoryBuffer.h"
21
22using namespace llvm;
23using namespace object;
24
25template<typename T>
Alexey Samsonove6388e62013-06-18 15:03:28 +000026static T getUniversalBinaryStruct(const char *Ptr) {
27 T Res;
28 memcpy(&Res, Ptr, sizeof(T));
29 // Universal binary headers have big-endian byte order.
30 if (sys::IsLittleEndianHost)
Chris Bieneman8e783eb2016-06-22 22:19:08 +000031 swapStruct(Res);
Alexey Samsonove6388e62013-06-18 15:03:28 +000032 return Res;
33}
34
35MachOUniversalBinary::ObjectForArch::ObjectForArch(
36 const MachOUniversalBinary *Parent, uint32_t Index)
37 : Parent(Parent), Index(Index) {
Kevin Enderby4b8fc282014-06-18 22:04:40 +000038 if (!Parent || Index >= Parent->getNumberOfObjects()) {
Alexey Samsonove6388e62013-06-18 15:03:28 +000039 clear();
40 } else {
41 // Parse object header.
42 StringRef ParentData = Parent->getData();
Kevin Enderbyeb6d1102016-06-20 22:16:18 +000043 if (Parent->getMagic() == MachO::FAT_MAGIC) {
44 const char *HeaderPos = ParentData.begin() + sizeof(MachO::fat_header) +
45 Index * sizeof(MachO::fat_arch);
46 Header = getUniversalBinaryStruct<MachO::fat_arch>(HeaderPos);
47 if (ParentData.size() < Header.offset + Header.size) {
48 clear();
49 }
50 } else { // Parent->getMagic() == MachO::FAT_MAGIC_64
51 const char *HeaderPos = ParentData.begin() + sizeof(MachO::fat_header) +
52 Index * sizeof(MachO::fat_arch_64);
53 Header64 = getUniversalBinaryStruct<MachO::fat_arch_64>(HeaderPos);
54 if (ParentData.size() < Header64.offset + Header64.size) {
55 clear();
56 }
Alexey Samsonove6388e62013-06-18 15:03:28 +000057 }
58 }
59}
60
Kevin Enderby9acb1092016-05-31 20:35:34 +000061Expected<std::unique_ptr<MachOObjectFile>>
Rafael Espindola4f7932b2014-06-23 20:41:02 +000062MachOUniversalBinary::ObjectForArch::getAsObjectFile() const {
Frederic Riss6eb30ee2015-08-03 00:10:33 +000063 if (!Parent)
Kevin Enderby9acb1092016-05-31 20:35:34 +000064 return errorCodeToError(object_error::parse_failed);
Frederic Riss6eb30ee2015-08-03 00:10:33 +000065
66 StringRef ParentData = Parent->getData();
Kevin Enderbyeb6d1102016-06-20 22:16:18 +000067 StringRef ObjectData;
68 if (Parent->getMagic() == MachO::FAT_MAGIC)
69 ObjectData = ParentData.substr(Header.offset, Header.size);
70 else // Parent->getMagic() == MachO::FAT_MAGIC_64
71 ObjectData = ParentData.substr(Header64.offset, Header64.size);
Frederic Riss6eb30ee2015-08-03 00:10:33 +000072 StringRef ObjectName = Parent->getFileName();
73 MemoryBufferRef ObjBuffer(ObjectData, ObjectName);
Kevin Enderby9acb1092016-05-31 20:35:34 +000074 return ObjectFile::createMachOObjectFile(ObjBuffer);
Alexey Samsonove6388e62013-06-18 15:03:28 +000075}
76
Rafael Espindola0bfe8282014-12-09 21:05:36 +000077ErrorOr<std::unique_ptr<Archive>>
78MachOUniversalBinary::ObjectForArch::getAsArchive() const {
79 if (!Parent)
80 return object_error::parse_failed;
81
82 StringRef ParentData = Parent->getData();
Kevin Enderbyeb6d1102016-06-20 22:16:18 +000083 StringRef ObjectData;
84 if (Parent->getMagic() == MachO::FAT_MAGIC)
85 ObjectData = ParentData.substr(Header.offset, Header.size);
86 else // Parent->getMagic() == MachO::FAT_MAGIC_64
87 ObjectData = ParentData.substr(Header64.offset, Header64.size);
Rafael Espindola0bfe8282014-12-09 21:05:36 +000088 StringRef ObjectName = Parent->getFileName();
89 MemoryBufferRef ObjBuffer(ObjectData, ObjectName);
90 return Archive::create(ObjBuffer);
Kevin Enderbye858a652014-05-14 21:18:50 +000091}
92
Alexey Samsonove6388e62013-06-18 15:03:28 +000093void MachOUniversalBinary::anchor() { }
94
David Blaikie1f76e522014-09-03 17:41:05 +000095ErrorOr<std::unique_ptr<MachOUniversalBinary>>
Rafael Espindola48af1c22014-08-19 18:44:46 +000096MachOUniversalBinary::create(MemoryBufferRef Source) {
Rafael Espindoladb4ed0b2014-06-13 02:24:39 +000097 std::error_code EC;
Ahmed Charles56440fd2014-03-06 05:51:42 +000098 std::unique_ptr<MachOUniversalBinary> Ret(
Rafael Espindola48af1c22014-08-19 18:44:46 +000099 new MachOUniversalBinary(Source, EC));
Rafael Espindola692410e2014-01-21 23:06:54 +0000100 if (EC)
101 return EC;
David Blaikie1f76e522014-09-03 17:41:05 +0000102 return std::move(Ret);
Rafael Espindola692410e2014-01-21 23:06:54 +0000103}
104
Rafael Espindola48af1c22014-08-19 18:44:46 +0000105MachOUniversalBinary::MachOUniversalBinary(MemoryBufferRef Source,
Rafael Espindoladb4ed0b2014-06-13 02:24:39 +0000106 std::error_code &ec)
Kevin Enderbyeb6d1102016-06-20 22:16:18 +0000107 : Binary(Binary::ID_MachOUniversalBinary, Source), Magic(0),
108 NumberOfObjects(0) {
Rafael Espindola48af1c22014-08-19 18:44:46 +0000109 if (Data.getBufferSize() < sizeof(MachO::fat_header)) {
Alexey Samsonove6388e62013-06-18 15:03:28 +0000110 ec = object_error::invalid_file_type;
111 return;
112 }
113 // Check for magic value and sufficient header size.
114 StringRef Buf = getData();
Charles Davis8bdfafd2013-09-01 04:28:48 +0000115 MachO::fat_header H= getUniversalBinaryStruct<MachO::fat_header>(Buf.begin());
Kevin Enderbyeb6d1102016-06-20 22:16:18 +0000116 Magic = H.magic;
Charles Davis8bdfafd2013-09-01 04:28:48 +0000117 NumberOfObjects = H.nfat_arch;
Kevin Enderbyeb6d1102016-06-20 22:16:18 +0000118 uint32_t MinSize = sizeof(MachO::fat_header);
119 if (Magic == MachO::FAT_MAGIC)
120 MinSize += sizeof(MachO::fat_arch) * NumberOfObjects;
121 else if (Magic == MachO::FAT_MAGIC_64)
122 MinSize += sizeof(MachO::fat_arch_64) * NumberOfObjects;
123 else {
124 ec = object_error::parse_failed;
125 return;
126 }
127 if (Buf.size() < MinSize) {
Alexey Samsonove6388e62013-06-18 15:03:28 +0000128 ec = object_error::parse_failed;
129 return;
130 }
Rui Ueyama7d099192015-06-09 15:20:42 +0000131 ec = std::error_code();
Alexey Samsonove6388e62013-06-18 15:03:28 +0000132}
133
Kevin Enderby9acb1092016-05-31 20:35:34 +0000134Expected<std::unique_ptr<MachOObjectFile>>
Frederic Rissebc162a2015-06-22 21:33:24 +0000135MachOUniversalBinary::getObjectForArch(StringRef ArchName) const {
136 if (Triple(ArchName).getArch() == Triple::ArchType::UnknownArch)
Kevin Enderby9acb1092016-05-31 20:35:34 +0000137 return errorCodeToError(object_error::arch_not_found);
Frederic Rissebc162a2015-06-22 21:33:24 +0000138
Alexey Samsonove6388e62013-06-18 15:03:28 +0000139 for (object_iterator I = begin_objects(), E = end_objects(); I != E; ++I) {
Frederic Rissebc162a2015-06-22 21:33:24 +0000140 if (I->getArchTypeName() == ArchName)
Rafael Espindola4f7932b2014-06-23 20:41:02 +0000141 return I->getAsObjectFile();
Alexey Samsonove6388e62013-06-18 15:03:28 +0000142 }
Kevin Enderby9acb1092016-05-31 20:35:34 +0000143 return errorCodeToError(object_error::arch_not_found);
Alexey Samsonove6388e62013-06-18 15:03:28 +0000144}