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 | |
53 | namespace { |
54 | |
55 | const 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 | |
78 | const 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 | |
90 | namespace google_breakpad { |
91 | |
92 | const 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 | |
109 | const 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. |
137 | namespace { |
138 | |
139 | enum 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. |
153 | const 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 | |
207 | const 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 | |
227 | const 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 | |
236 | const 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 | |
252 | struct 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 | |