1// Copyright (c) 2012, Google Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following disclaimer
12// in the documentation and/or other materials provided with the
13// distribution.
14// * Neither the name of Google Inc. nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30#include "common/mac/arch_utilities.h"
31
32#include <mach-o/arch.h>
33#include <mach-o/fat.h>
34#include <stdio.h>
35#include <string.h>
36
37#ifndef CPU_SUBTYPE_ARM_V7S
38#define CPU_SUBTYPE_ARM_V7S (static_cast<cpu_subtype_t>(11))
39#endif // CPU_SUBTYPE_ARM_V7S
40
41#ifndef CPU_TYPE_ARM64
42#define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64)
43#endif // CPU_TYPE_ARM64
44
45#ifndef CPU_SUBTYPE_ARM64_ALL
46#define CPU_SUBTYPE_ARM64_ALL (static_cast<cpu_subtype_t>(0))
47#endif // CPU_SUBTYPE_ARM64_ALL
48
49#ifndef CPU_SUBTYPE_ARM64_E
50#define CPU_SUBTYPE_ARM64_E (static_cast<cpu_subtype_t>(2))
51#endif // CPU_SUBTYPE_ARM64_E
52
53namespace {
54
55const NXArchInfo* ArchInfo_arm64(cpu_subtype_t cpu_subtype) {
56 const char* name = NULL;
57 switch (cpu_subtype) {
58 case CPU_SUBTYPE_ARM64_ALL:
59 name = "arm64";
60 break;
61 case CPU_SUBTYPE_ARM64_E:
62 name = "arm64e";
63 break;
64 default:
65 return NULL;
66 }
67
68 NXArchInfo* arm64 = new NXArchInfo;
69 *arm64 = *NXGetArchInfoFromCpuType(CPU_TYPE_ARM,
70 CPU_SUBTYPE_ARM_V7);
71 arm64->name = name;
72 arm64->cputype = CPU_TYPE_ARM64;
73 arm64->cpusubtype = cpu_subtype;
74 arm64->description = "arm 64";
75 return arm64;
76}
77
78const NXArchInfo* ArchInfo_armv7s() {
79 NXArchInfo* armv7s = new NXArchInfo;
80 *armv7s = *NXGetArchInfoFromCpuType(CPU_TYPE_ARM,
81 CPU_SUBTYPE_ARM_V7);
82 armv7s->name = "armv7s";
83 armv7s->cpusubtype = CPU_SUBTYPE_ARM_V7S;
84 armv7s->description = "arm v7s";
85 return armv7s;
86}
87
88} // namespace
89
90namespace google_breakpad {
91
92const NXArchInfo* BreakpadGetArchInfoFromName(const char* arch_name) {
93 // TODO: Remove this when the OS knows about arm64.
94 if (!strcmp("arm64", arch_name))
95 return BreakpadGetArchInfoFromCpuType(CPU_TYPE_ARM64,
96 CPU_SUBTYPE_ARM64_ALL);
97
98 if (!strcmp("arm64e", arch_name))
99 return BreakpadGetArchInfoFromCpuType(CPU_TYPE_ARM64,
100 CPU_SUBTYPE_ARM64_E);
101
102 // TODO: Remove this when the OS knows about armv7s.
103 if (!strcmp("armv7s", arch_name))
104 return BreakpadGetArchInfoFromCpuType(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7S);
105
106 return NXGetArchInfoFromName(arch_name);
107}
108
109const NXArchInfo* BreakpadGetArchInfoFromCpuType(cpu_type_t cpu_type,
110 cpu_subtype_t cpu_subtype) {
111 // TODO: Remove this when the OS knows about arm64.
112 if (cpu_type == CPU_TYPE_ARM64 && cpu_subtype == CPU_SUBTYPE_ARM64_ALL) {
113 static const NXArchInfo* arm64 = ArchInfo_arm64(cpu_subtype);
114 return arm64;
115 }
116
117 if (cpu_type == CPU_TYPE_ARM64 && cpu_subtype == CPU_SUBTYPE_ARM64_E) {
118 static const NXArchInfo* arm64e = ArchInfo_arm64(cpu_subtype);
119 return arm64e;
120 }
121
122 // TODO: Remove this when the OS knows about armv7s.
123 if (cpu_type == CPU_TYPE_ARM && cpu_subtype == CPU_SUBTYPE_ARM_V7S) {
124 static const NXArchInfo* armv7s = ArchInfo_armv7s();
125 return armv7s;
126 }
127
128 return NXGetArchInfoFromCpuType(cpu_type, cpu_subtype);
129}
130
131} // namespace google_breakpad
132
133// TODO(crbug.com/1242776): The "#ifndef __APPLE__" should be here, but the
134// system version of NXGetLocalArchInfo returns incorrect information on
135// x86_64 machines (treating them as just x86), so use the Breakpad version
136// all the time for now.
137namespace {
138
139enum Architecture {
140 kArch_i386 = 0,
141 kArch_x86_64,
142 kArch_x86_64h,
143 kArch_arm,
144 kArch_arm64,
145 kArch_arm64e,
146 kArch_ppc,
147 // This must be last.
148 kNumArchitectures
149};
150
151// enum Architecture above and kKnownArchitectures below
152// must be kept in sync.
153const NXArchInfo kKnownArchitectures[] = {
154 {
155 "i386",
156 CPU_TYPE_I386,
157 CPU_SUBTYPE_I386_ALL,
158 NX_LittleEndian,
159 "Intel 80x86"
160 },
161 {
162 "x86_64",
163 CPU_TYPE_X86_64,
164 CPU_SUBTYPE_X86_64_ALL,
165 NX_LittleEndian,
166 "Intel x86-64"
167 },
168 {
169 "x86_64h",
170 CPU_TYPE_X86_64,
171 CPU_SUBTYPE_X86_64_H,
172 NX_LittleEndian,
173 "Intel x86-64h Haswell"
174 },
175 {
176 "arm",
177 CPU_TYPE_ARM,
178 CPU_SUBTYPE_ARM_ALL,
179 NX_LittleEndian,
180 "ARM"
181 },
182 {
183 "arm64",
184 CPU_TYPE_ARM64,
185 CPU_SUBTYPE_ARM64_ALL,
186 NX_LittleEndian,
187 "ARM64"
188 },
189 {
190 "arm64e",
191 CPU_TYPE_ARM64,
192 CPU_SUBTYPE_ARM64_E,
193 NX_LittleEndian,
194 "ARM64e"
195 },
196 {
197 "ppc",
198 CPU_TYPE_POWERPC,
199 CPU_SUBTYPE_POWERPC_ALL,
200 NX_BigEndian,
201 "PowerPC"
202 }
203};
204
205} // namespace
206
207const NXArchInfo *NXGetLocalArchInfo(void) {
208 Architecture arch;
209#if defined(__i386__)
210 arch = kArch_i386;
211#elif defined(__x86_64__)
212 arch = kArch_x86_64;
213#elif defined(__arm64)
214 arch = kArch_arm64;
215#elif defined(__arm__)
216 arch = kArch_arm;
217#elif defined(__powerpc__)
218 arch = kArch_ppc;
219#else
220 #error "Unsupported CPU architecture"
221#endif
222 return &kKnownArchitectures[arch];
223}
224
225#ifndef __APPLE__
226
227const NXArchInfo *NXGetArchInfoFromName(const char *name) {
228 for (int arch = 0; arch < kNumArchitectures; ++arch) {
229 if (!strcmp(name, kKnownArchitectures[arch].name)) {
230 return &kKnownArchitectures[arch];
231 }
232 }
233 return NULL;
234}
235
236const NXArchInfo *NXGetArchInfoFromCpuType(cpu_type_t cputype,
237 cpu_subtype_t cpusubtype) {
238 const NXArchInfo *candidate = NULL;
239 for (int arch = 0; arch < kNumArchitectures; ++arch) {
240 if (kKnownArchitectures[arch].cputype == cputype) {
241 if (kKnownArchitectures[arch].cpusubtype == cpusubtype) {
242 return &kKnownArchitectures[arch];
243 }
244 if (!candidate) {
245 candidate = &kKnownArchitectures[arch];
246 }
247 }
248 }
249 return candidate;
250}
251
252struct fat_arch *NXFindBestFatArch(cpu_type_t cputype,
253 cpu_subtype_t cpusubtype,
254 struct fat_arch *fat_archs,
255 uint32_t nfat_archs) {
256 struct fat_arch *candidate = NULL;
257 for (uint32_t f = 0; f < nfat_archs; ++f) {
258 if (fat_archs[f].cputype == cputype) {
259 if (fat_archs[f].cpusubtype == cpusubtype) {
260 return &fat_archs[f];
261 }
262 if (!candidate) {
263 candidate = &fat_archs[f];
264 }
265 }
266 }
267 return candidate;
268}
269#endif // !__APPLE__
270