Commit | Line | Data |
---|---|---|
4a81b561 DHW |
1 | /* BFD library support routines for architectures. */ |
2 | ||
3 | /* Copyright (C) 1990, 1991 Free Software Foundation, Inc. | |
4 | ||
5 | This file is part of BFD, the Binary File Diddler. | |
6 | ||
7 | BFD is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 1, or (at your option) | |
10 | any later version. | |
11 | ||
12 | BFD is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with BFD; see the file COPYING. If not, write to | |
19 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
20 | ||
21 | /* $Id$ */ | |
22 | ||
23 | #include "sysdep.h" | |
24 | #include "bfd.h" | |
25 | #include "archures.h" | |
26 | ||
27 | static char *prt_num_mach (); | |
28 | static boolean scan_num_mach (); | |
29 | static char *prt_960_mach (); | |
30 | static boolean scan_960_mach (); | |
31 | ||
32 | struct arch_print { | |
33 | enum bfd_architecture arch; | |
34 | char *astr; | |
35 | char *(*mach_print)(); | |
36 | boolean (*mach_scan)(); | |
37 | } arch_print[] = { | |
38 | ||
39 | {bfd_arch_unknown, "unknown", prt_num_mach, scan_num_mach}, | |
40 | {bfd_arch_obscure, "obscure", prt_num_mach, scan_num_mach}, | |
41 | {bfd_arch_m68k, "m68k", prt_num_mach, scan_num_mach}, | |
42 | {bfd_arch_vax, "vax", prt_num_mach, scan_num_mach}, | |
43 | {bfd_arch_i960, "i960", prt_960_mach, scan_960_mach}, | |
44 | {bfd_arch_a29k, "a29k", prt_num_mach, scan_num_mach}, | |
45 | {bfd_arch_sparc, "sparc", prt_num_mach, scan_num_mach}, | |
46 | {bfd_arch_mips, "mips", prt_num_mach, scan_num_mach}, | |
47 | {bfd_arch_i386, "i386", prt_num_mach, scan_num_mach}, | |
48 | {bfd_arch_ns32k, "ns32k", prt_num_mach, scan_num_mach}, | |
49 | {bfd_arch_tahoe, "tahoe", prt_num_mach, scan_num_mach}, | |
50 | {bfd_arch_i860, "i860", prt_num_mach, scan_num_mach}, | |
51 | {bfd_arch_romp, "romp", prt_num_mach, scan_num_mach}, | |
52 | {bfd_arch_alliant, "alliant", prt_num_mach, scan_num_mach}, | |
53 | {bfd_arch_convex, "convex", prt_num_mach, scan_num_mach}, | |
54 | {bfd_arch_m88k, "m88k", prt_num_mach, scan_num_mach}, | |
55 | {bfd_arch_pyramid, "pyramid", prt_num_mach, scan_num_mach}, | |
4cddd1c9 SC |
56 | {bfd_arch_h8_300, "H8/300", prt_num_mach, scan_num_mach}, |
57 | {bfd_arch_unknown, (char *)0, prt_num_mach, scan_num_mach}, | |
4a81b561 DHW |
58 | }; |
59 | ||
60 | /* Return a printable string representing the architecture and machine | |
61 | type. The result is only good until the next call to | |
62 | bfd_printable_arch_mach. */ | |
63 | ||
64 | char * | |
65 | bfd_printable_arch_mach (arch, machine) | |
66 | enum bfd_architecture arch; | |
67 | unsigned long machine; | |
68 | { | |
69 | struct arch_print *ap; | |
70 | ||
71 | for (ap = arch_print; ap->astr; ap++) { | |
72 | if (ap->arch == arch) { | |
73 | if (machine == 0) | |
74 | return ap->astr; | |
75 | return (*ap->mach_print)(ap, machine); | |
76 | } | |
77 | } | |
78 | return "UNKNOWN!"; | |
79 | } | |
80 | ||
81 | static char * | |
82 | prt_num_mach (ap, machine) | |
83 | struct arch_print *ap; | |
84 | unsigned long machine; | |
85 | { | |
86 | static char result[20]; | |
87 | ||
88 | sprintf(result, "%s:%ld", ap->astr, (long) machine); | |
89 | return result; | |
90 | } | |
91 | ||
92 | /* Scan a string and attempt to turn it into an archive and machine type | |
93 | combination. */ | |
94 | ||
95 | boolean | |
4cddd1c9 SC |
96 | DEFUN(bfd_scan_arch_mach,(string, archp, machinep), |
97 | CONST char *string AND | |
98 | enum bfd_architecture *archp AND | |
99 | unsigned long *machinep) | |
4a81b561 DHW |
100 | { |
101 | struct arch_print *ap; | |
102 | int len; | |
103 | ||
104 | /* First look for an architecture, possibly followed by machtype. */ | |
105 | for (ap = arch_print; ap->astr; ap++) { | |
106 | if (ap->astr[0] != string[0]) | |
107 | continue; | |
108 | len = strlen (ap->astr); | |
109 | if (!strncmp (ap->astr, string, len)) { | |
110 | /* We found the architecture, now see about the machine type */ | |
111 | if (archp) | |
112 | *archp = ap->arch; | |
113 | if (string[len] != '\0') { | |
114 | if (ap->mach_scan (string+len, ap, archp, machinep, 1)) | |
115 | return true; | |
116 | } | |
117 | if (machinep) | |
118 | *machinep = 0; | |
119 | return true; | |
120 | } | |
121 | } | |
122 | ||
123 | /* Couldn't find an architecture -- try for just a machine type */ | |
124 | for (ap = arch_print; ap->astr; ap++) { | |
125 | if (ap->mach_scan (string, ap, archp, machinep, 0)) | |
126 | return true; | |
127 | } | |
128 | ||
129 | return false; | |
130 | } | |
131 | ||
132 | static boolean | |
133 | scan_num_mach (string, ap, archp, machinep, archspec) | |
134 | char *string; | |
135 | struct arch_print *ap; | |
136 | enum bfd_architecture *archp; | |
137 | unsigned long *machinep; | |
138 | int archspec; | |
139 | { | |
140 | enum bfd_architecture arch; | |
141 | unsigned long machine; | |
142 | char achar; | |
143 | ||
144 | if (archspec) { | |
145 | ||
146 | /* Architecture already specified, now go for machine type. */ | |
147 | if (string[0] != ':') | |
148 | return false; | |
149 | /* We'll take any valid number that occupies the entire string */ | |
150 | if (1 != sscanf (string+1, "%lu%c", &machine, &achar)) | |
151 | return false; | |
152 | arch = ap->arch; | |
153 | ||
154 | } else { | |
155 | ||
156 | /* We couldn't identify an architecture prefix. Perhaps the entire | |
157 | thing is a machine type. Be a lot picker. */ | |
158 | if (1 != sscanf (string, "%lu%c", &machine, &achar)) | |
159 | return false; | |
160 | switch (machine) { | |
161 | case 68010: | |
162 | case 68020: | |
163 | case 68030: | |
164 | case 68040: | |
165 | case 68332: | |
166 | case 68050: arch = bfd_arch_m68k; break; | |
167 | case 68000: arch = bfd_arch_m68k; machine = 0; break; | |
168 | ||
169 | case 80960: | |
170 | case 960: arch = bfd_arch_i960; machine = 0; break; | |
171 | ||
172 | case 386: | |
173 | case 80386: arch = bfd_arch_i386; machine = 0; break; | |
174 | case 486: arch = bfd_arch_i386; break; | |
175 | ||
176 | case 29000: arch = bfd_arch_a29k; machine = 0; break; | |
177 | ||
178 | case 32016: | |
179 | case 32032: | |
180 | case 32132: | |
181 | case 32232: | |
182 | case 32332: | |
183 | case 32432: | |
184 | case 32532: arch = bfd_arch_ns32k; break; | |
185 | case 32000: arch = bfd_arch_ns32k; machine = 0; break; | |
186 | ||
187 | case 860: | |
188 | case 80860: arch = bfd_arch_i860; machine = 0; break; | |
189 | ||
190 | default: return false; | |
191 | } | |
192 | } | |
193 | ||
194 | if (archp) | |
195 | *archp = arch; | |
196 | if (machinep) | |
197 | *machinep = machine; | |
198 | return true; | |
199 | } | |
200 | \f | |
201 | /* Intel 960 machine variants. */ | |
202 | ||
203 | static char * | |
204 | prt_960_mach (ap, machine) | |
205 | struct arch_print *ap; | |
206 | unsigned long machine; | |
207 | { | |
208 | static char result[20]; | |
209 | char *str; | |
210 | ||
211 | switch (machine) { | |
212 | case bfd_mach_i960_core: str = "core"; break; | |
213 | case bfd_mach_i960_kb_sb: str = "kb"; break; | |
214 | case bfd_mach_i960_mc: str = "mc"; break; | |
215 | case bfd_mach_i960_xa: str = "xa"; break; | |
216 | case bfd_mach_i960_ca: str = "ca"; break; | |
217 | case bfd_mach_i960_ka_sa: str = "ka"; break; | |
218 | default: | |
219 | return prt_num_mach (ap, machine); | |
220 | } | |
221 | sprintf (result, "%s:%s", ap->astr, str); | |
222 | return result; | |
223 | } | |
224 | ||
225 | static boolean | |
226 | scan_960_mach (string, ap, archp, machinep, archspec) | |
227 | char *string; | |
228 | struct arch_print *ap; | |
229 | enum bfd_architecture *archp; | |
230 | unsigned long *machinep; | |
231 | int archspec; | |
232 | { | |
233 | unsigned long machine; | |
234 | ||
235 | if (!archspec) | |
236 | return false; | |
237 | if (string[0] != ':') | |
238 | return false; | |
239 | string++; | |
240 | if (string[0] == '\0') | |
241 | return false; | |
242 | if (string[0] == 'c' && string[1] == 'o' && string[2] == 'r' && | |
243 | string[3] == 'e' && string[4] == '\0') | |
244 | machine = bfd_mach_i960_core; | |
245 | else if (string[1] == '\0' || string[2] != '\0') /* rest are 2-char */ | |
246 | return false; | |
247 | else if (string[0] == 'k' && string[1] == 'b') | |
248 | machine = bfd_mach_i960_kb_sb; | |
249 | else if (string[0] == 's' && string[1] == 'b') | |
250 | machine = bfd_mach_i960_kb_sb; | |
251 | else if (string[0] == 'm' && string[1] == 'c') | |
252 | machine = bfd_mach_i960_mc; | |
253 | else if (string[0] == 'x' && string[1] == 'a') | |
254 | machine = bfd_mach_i960_xa; | |
255 | else if (string[0] == 'c' && string[1] == 'a') | |
256 | machine = bfd_mach_i960_ca; | |
257 | else if (string[0] == 'k' && string[1] == 'a') | |
258 | machine = bfd_mach_i960_ka_sa; | |
259 | else if (string[0] == 's' && string[1] == 'a') | |
260 | machine = bfd_mach_i960_ka_sa; | |
261 | else | |
262 | return false; | |
263 | ||
264 | if (archp) | |
265 | *archp = ap->arch; | |
266 | if (machinep) | |
267 | *machinep = machine; | |
268 | return true; | |
269 | } | |
270 | ||
271 | ||
272 | \f | |
273 | /* Determine whether two BFDs' architectures and machine types are | |
274 | compatible. Return merged architecture and machine type if nonnull | |
275 | pointers. */ | |
276 | ||
277 | boolean | |
278 | bfd_arch_compatible (abfd, bbfd, archp, machinep) | |
279 | bfd *abfd; | |
280 | bfd *bbfd; | |
281 | enum bfd_architecture *archp; | |
282 | unsigned long *machinep; | |
283 | { | |
284 | enum bfd_architecture archa, archb; | |
285 | unsigned long macha, machb; | |
286 | int pick_a; | |
287 | ||
288 | archa = bfd_get_architecture (abfd); | |
289 | archb = bfd_get_architecture (bbfd); | |
290 | macha = bfd_get_machine (abfd); | |
291 | machb = bfd_get_machine (bbfd); | |
292 | ||
293 | if (archb == bfd_arch_unknown) | |
294 | pick_a = 1; | |
295 | else if (archa == bfd_arch_unknown) | |
296 | pick_a = 0; | |
297 | else if (archa != archb) | |
298 | return false; /* Not compatible */ | |
299 | else { | |
300 | /* Architectures are the same. Check machine types. */ | |
301 | if (macha == machb) /* Same machine type */ | |
302 | pick_a = 1; | |
303 | else if (machb == 0) /* B is default */ | |
304 | pick_a = 1; | |
305 | else if (macha == 0) /* A is default */ | |
306 | pick_a = 0; | |
307 | else switch (archa) { | |
308 | /* If particular machine types of one architecture are not | |
309 | compatible with each other, this is the place to put those tests | |
310 | (returning false if incompatible). */ | |
fc723380 JG |
311 | |
312 | case bfd_arch_i960: | |
313 | /* The i960 has two distinct subspecies which may not interbreed: | |
314 | CORE CA | |
315 | CORE KA KB MC | |
316 | Any architecture on the same line is compatible, the one on | |
317 | the right is the least restrictive. */ | |
318 | /* So, if either is a ca then the other must be a be core or ca */ | |
319 | if (macha == bfd_mach_i960_ca) { | |
320 | if (machb != bfd_mach_i960_ca && | |
321 | machb != bfd_mach_i960_core) { | |
322 | return false; | |
323 | } | |
324 | pick_a = 1; | |
4a81b561 | 325 | } |
fc723380 JG |
326 | else if (machb == bfd_mach_i960_ca) { |
327 | if (macha != bfd_mach_i960_ca && | |
328 | macha != bfd_mach_i960_core) { | |
329 | return false; | |
330 | } | |
331 | pick_a = 0; | |
4a81b561 | 332 | } |
fc723380 JG |
333 | else { |
334 | /* This must be from the bottom row, so take the higest */ | |
335 | pick_a = (macha > machb); | |
336 | } | |
337 | break; | |
4a81b561 DHW |
338 | |
339 | /* For these chips, as far as we care, "lower" numbers are included | |
340 | by "higher" numbers, e.g. merge 68010 and 68020 into 68020, | |
341 | 386 and 486 into 486, etc. This will need to change | |
342 | if&when we care about things like 68332. */ | |
343 | case bfd_arch_m68k: | |
344 | case bfd_arch_ns32k: | |
345 | case bfd_arch_i386: | |
346 | pick_a = (macha > machb); | |
347 | break; | |
348 | ||
349 | /* By default, pick first file's type, for lack of something better. */ | |
350 | default: | |
351 | pick_a = 1; | |
352 | } | |
353 | } | |
354 | ||
355 | /* Set result based on our pick */ | |
356 | if (!pick_a) { | |
357 | archa = archb; | |
358 | macha = machb; | |
359 | } | |
360 | if (archp) | |
361 | *archp = archa; | |
362 | if (machinep) | |
363 | *machinep = macha; | |
364 | ||
365 | return true; | |
366 | } |