1//===-- llvm/BinaryFormat/MachO.cpp - The MachO file format -----*- C++/-*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "llvm/BinaryFormat/MachO.h"
10#include "llvm/TargetParser/ARMTargetParser.h"
11#include "llvm/TargetParser/Triple.h"
12
13using namespace llvm;
14
15static MachO::CPUSubTypeX86 getX86SubType(const Triple &T) {
16 assert(T.isX86());
17 if (T.isArch32Bit())
18 return MachO::CPU_SUBTYPE_I386_ALL;
19
20 assert(T.isArch64Bit());
21 if (T.getArchName() == "x86_64h")
22 return MachO::CPU_SUBTYPE_X86_64_H;
23 return MachO::CPU_SUBTYPE_X86_64_ALL;
24}
25
26static MachO::CPUSubTypeARM getARMSubType(const Triple &T) {
27 assert(T.isARM() || T.isThumb());
28 StringRef Arch = T.getArchName();
29 ARM::ArchKind AK = ARM::parseArch(Arch);
30 switch (AK) {
31 default:
32 return MachO::CPU_SUBTYPE_ARM_V7;
33 case ARM::ArchKind::ARMV4T:
34 return MachO::CPU_SUBTYPE_ARM_V4T;
35 case ARM::ArchKind::ARMV5T:
36 case ARM::ArchKind::ARMV5TE:
37 case ARM::ArchKind::ARMV5TEJ:
38 return MachO::CPU_SUBTYPE_ARM_V5;
39 case ARM::ArchKind::ARMV6:
40 case ARM::ArchKind::ARMV6K:
41 return MachO::CPU_SUBTYPE_ARM_V6;
42 case ARM::ArchKind::ARMV7A:
43 return MachO::CPU_SUBTYPE_ARM_V7;
44 case ARM::ArchKind::ARMV7S:
45 return MachO::CPU_SUBTYPE_ARM_V7S;
46 case ARM::ArchKind::ARMV7K:
47 return MachO::CPU_SUBTYPE_ARM_V7K;
48 case ARM::ArchKind::ARMV6M:
49 return MachO::CPU_SUBTYPE_ARM_V6M;
50 case ARM::ArchKind::ARMV7M:
51 return MachO::CPU_SUBTYPE_ARM_V7M;
52 case ARM::ArchKind::ARMV7EM:
53 return MachO::CPU_SUBTYPE_ARM_V7EM;
54 case ARM::ArchKind::ARMV8MBaseline:
55 return MachO::CPU_SUBTYPE_ARM_V8M_BASE;
56 case ARM::ArchKind::ARMV8MMainline:
57 return MachO::CPU_SUBTYPE_ARM_V8M_MAIN;
58 case ARM::ArchKind::ARMV8_1MMainline:
59 return MachO::CPU_SUBTYPE_ARM_V8_1M_MAIN;
60 }
61}
62
63static MachO::CPUSubTypeARM64 getARM64SubType(const Triple &T) {
64 assert(T.isAArch64());
65 if (T.isArch32Bit())
66 return (MachO::CPUSubTypeARM64)MachO::CPU_SUBTYPE_ARM64_32_V8;
67 if (T.isArm64e())
68 return MachO::CPU_SUBTYPE_ARM64E;
69 if (T.isArm64e_x1())
70 return MachO::CPU_SUBTYPE_ARM64E_X1;
71
72 return MachO::CPU_SUBTYPE_ARM64_ALL;
73}
74
75static MachO::CPUSubTypePowerPC getPowerPCSubType(const Triple &T) {
76 return MachO::CPU_SUBTYPE_POWERPC_ALL;
77}
78
79static Error unsupported(const char *Str, const Triple &T) {
80 return createStringError(EC: std::errc::invalid_argument,
81 Fmt: "Unsupported triple for mach-o cpu %s: %s", Vals: Str,
82 Vals: T.str().c_str());
83}
84
85static MachO::CPUSubTypeRISCV getRISCVSubType(const Triple &T) {
86 return MachO::CPU_SUBTYPE_RISCV_ALL;
87}
88
89Expected<uint32_t> MachO::getCPUType(const Triple &T) {
90 if (!T.isOSBinFormatMachO())
91 return unsupported(Str: "type", T);
92 if (T.isX86() && T.isArch32Bit())
93 return MachO::CPU_TYPE_X86;
94 if (T.isX86() && T.isArch64Bit())
95 return MachO::CPU_TYPE_X86_64;
96 if (T.isARM() || T.isThumb())
97 return MachO::CPU_TYPE_ARM;
98 if (T.isAArch64())
99 return T.isArch32Bit() ? MachO::CPU_TYPE_ARM64_32 : MachO::CPU_TYPE_ARM64;
100 if (T.getArch() == Triple::ppc)
101 return MachO::CPU_TYPE_POWERPC;
102 if (T.getArch() == Triple::ppc64)
103 return MachO::CPU_TYPE_POWERPC64;
104 if (T.getArch() == Triple::riscv32)
105 return MachO::CPU_TYPE_RISCV;
106 return unsupported(Str: "type", T);
107}
108
109Expected<uint32_t> MachO::getCPUSubType(const Triple &T) {
110 if (!T.isOSBinFormatMachO())
111 return unsupported(Str: "subtype", T);
112 if (T.isX86())
113 return getX86SubType(T);
114 if (T.isARM() || T.isThumb())
115 return getARMSubType(T);
116 if (T.isAArch64() || T.getArch() == Triple::aarch64_32)
117 return getARM64SubType(T);
118 if (T.getArch() == Triple::ppc || T.getArch() == Triple::ppc64)
119 return getPowerPCSubType(T);
120 if (T.getArch() == Triple::riscv32)
121 return getRISCVSubType(T);
122 return unsupported(Str: "subtype", T);
123}
124
125Expected<uint32_t> MachO::getCPUSubType(const Triple &T,
126 unsigned PtrAuthABIVersion,
127 bool PtrAuthKernelABIVersion) {
128 Expected<uint32_t> Result = MachO::getCPUSubType(T);
129 if (!Result)
130 return Result.takeError();
131 if (*Result != MachO::CPU_SUBTYPE_ARM64E)
132 return createStringError(
133 EC: std::errc::invalid_argument,
134 Fmt: "ptrauth ABI version is only supported on arm64e.");
135 if (PtrAuthABIVersion > 0xF)
136 return createStringError(
137 EC: std::errc::invalid_argument,
138 Fmt: "The ptrauth ABI version needs to fit within 4 bits.");
139 return CPU_SUBTYPE_ARM64E_WITH_PTRAUTH_VERSION(PtrAuthABIVersion,
140 PtrAuthKernelABIVersion);
141}
142