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 
ArchInfo_arm64(cpu_subtype_t cpu_subtype)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 
ArchInfo_armv7s()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 
BreakpadGetArchInfoFromName(const char * arch_name)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 
BreakpadGetArchInfoFromCpuType(cpu_type_t cpu_type,cpu_subtype_t cpu_subtype)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 #ifndef __APPLE__
134 namespace {
135 
136 enum Architecture {
137   kArch_i386 = 0,
138   kArch_x86_64,
139   kArch_x86_64h,
140   kArch_arm,
141   kArch_arm64,
142   kArch_arm64e,
143   kArch_ppc,
144   // This must be last.
145   kNumArchitectures
146 };
147 
148 // enum Architecture above and kKnownArchitectures below
149 // must be kept in sync.
150 const NXArchInfo kKnownArchitectures[] = {
151   {
152     "i386",
153     CPU_TYPE_I386,
154     CPU_SUBTYPE_I386_ALL,
155     NX_LittleEndian,
156     "Intel 80x86"
157   },
158   {
159     "x86_64",
160     CPU_TYPE_X86_64,
161     CPU_SUBTYPE_X86_64_ALL,
162     NX_LittleEndian,
163     "Intel x86-64"
164   },
165   {
166     "x86_64h",
167     CPU_TYPE_X86_64,
168     CPU_SUBTYPE_X86_64_H,
169     NX_LittleEndian,
170     "Intel x86-64h Haswell"
171   },
172   {
173     "arm",
174     CPU_TYPE_ARM,
175     CPU_SUBTYPE_ARM_ALL,
176     NX_LittleEndian,
177     "ARM"
178   },
179   {
180     "arm64",
181     CPU_TYPE_ARM64,
182     CPU_SUBTYPE_ARM64_ALL,
183     NX_LittleEndian,
184     "ARM64"
185   },
186   {
187     "arm64e",
188     CPU_TYPE_ARM64,
189     CPU_SUBTYPE_ARM64_E,
190     NX_LittleEndian,
191     "ARM64e"
192   },
193   {
194     "ppc",
195     CPU_TYPE_POWERPC,
196     CPU_SUBTYPE_POWERPC_ALL,
197     NX_BigEndian,
198     "PowerPC"
199   }
200 };
201 
202 }  // namespace
203 
NXGetLocalArchInfo(void)204 const NXArchInfo *NXGetLocalArchInfo(void) {
205   Architecture arch;
206 #if defined(__i386__)
207   arch = kArch_i386;
208 #elif defined(__x86_64__)
209   arch = kArch_x86_64;
210 #elif defined(__arm64)
211   arch = kArch_arm64;
212 #elif defined(__arm__)
213   arch = kArch_arm;
214 #elif defined(__powerpc__)
215   arch = kArch_ppc;
216 #else
217   #error "Unsupported CPU architecture"
218 #endif
219   return &kKnownArchitectures[arch];
220 }
221 
NXGetArchInfoFromName(const char * name)222 const NXArchInfo *NXGetArchInfoFromName(const char *name) {
223   for (int arch = 0; arch < kNumArchitectures; ++arch) {
224     if (!strcmp(name, kKnownArchitectures[arch].name)) {
225       return &kKnownArchitectures[arch];
226     }
227   }
228   return NULL;
229 }
230 
NXGetArchInfoFromCpuType(cpu_type_t cputype,cpu_subtype_t cpusubtype)231 const NXArchInfo *NXGetArchInfoFromCpuType(cpu_type_t cputype,
232                                            cpu_subtype_t cpusubtype) {
233   const NXArchInfo *candidate = NULL;
234   for (int arch = 0; arch < kNumArchitectures; ++arch) {
235     if (kKnownArchitectures[arch].cputype == cputype) {
236       if (kKnownArchitectures[arch].cpusubtype == cpusubtype) {
237         return &kKnownArchitectures[arch];
238       }
239       if (!candidate) {
240         candidate = &kKnownArchitectures[arch];
241       }
242     }
243   }
244   return candidate;
245 }
246 
NXFindBestFatArch(cpu_type_t cputype,cpu_subtype_t cpusubtype,struct fat_arch * fat_archs,uint32_t nfat_archs)247 struct fat_arch *NXFindBestFatArch(cpu_type_t cputype,
248                                    cpu_subtype_t cpusubtype,
249                                    struct fat_arch *fat_archs,
250                                    uint32_t nfat_archs) {
251   struct fat_arch *candidate = NULL;
252   for (uint32_t f = 0; f < nfat_archs; ++f) {
253     if (fat_archs[f].cputype == cputype) {
254       if (fat_archs[f].cpusubtype == cpusubtype) {
255         return &fat_archs[f];
256       }
257       if (!candidate) {
258         candidate = &fat_archs[f];
259       }
260     }
261   }
262   return candidate;
263 }
264 #endif  // !__APPLE__
265