diff options
Diffstat (limited to 'bfd/archures.c')
-rw-r--r-- | bfd/archures.c | 368 |
1 files changed, 368 insertions, 0 deletions
diff --git a/bfd/archures.c b/bfd/archures.c new file mode 100644 index 0000000..b7fdaf9 --- /dev/null +++ b/bfd/archures.c @@ -0,0 +1,368 @@ +/* BFD library support routines for architectures. */ + +/* Copyright (C) 1990, 1991 Free Software Foundation, Inc. + +This file is part of BFD, the Binary File Diddler. + +BFD is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +BFD is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BFD; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* $Id$ */ + +#include "sysdep.h" +#include "bfd.h" +#include "archures.h" + +static char *prt_num_mach (); +static boolean scan_num_mach (); +static char *prt_960_mach (); +static boolean scan_960_mach (); + +struct arch_print { + enum bfd_architecture arch; + char *astr; + char *(*mach_print)(); + boolean (*mach_scan)(); +} arch_print[] = { + + {bfd_arch_unknown, "unknown", prt_num_mach, scan_num_mach}, + {bfd_arch_obscure, "obscure", prt_num_mach, scan_num_mach}, + {bfd_arch_m68k, "m68k", prt_num_mach, scan_num_mach}, + {bfd_arch_vax, "vax", prt_num_mach, scan_num_mach}, + {bfd_arch_i960, "i960", prt_960_mach, scan_960_mach}, + {bfd_arch_a29k, "a29k", prt_num_mach, scan_num_mach}, + {bfd_arch_sparc, "sparc", prt_num_mach, scan_num_mach}, + {bfd_arch_mips, "mips", prt_num_mach, scan_num_mach}, + {bfd_arch_i386, "i386", prt_num_mach, scan_num_mach}, + {bfd_arch_ns32k, "ns32k", prt_num_mach, scan_num_mach}, + {bfd_arch_tahoe, "tahoe", prt_num_mach, scan_num_mach}, + {bfd_arch_i860, "i860", prt_num_mach, scan_num_mach}, + {bfd_arch_romp, "romp", prt_num_mach, scan_num_mach}, + {bfd_arch_alliant, "alliant", prt_num_mach, scan_num_mach}, + {bfd_arch_convex, "convex", prt_num_mach, scan_num_mach}, + {bfd_arch_m88k, "m88k", prt_num_mach, scan_num_mach}, + {bfd_arch_pyramid, "pyramid", prt_num_mach, scan_num_mach}, + {bfd_arch_unknown, (char *)0, prt_num_mach, scan_num_mach}, +}; + +/* Return a printable string representing the architecture and machine + type. The result is only good until the next call to + bfd_printable_arch_mach. */ + +char * +bfd_printable_arch_mach (arch, machine) + enum bfd_architecture arch; + unsigned long machine; +{ + struct arch_print *ap; + + for (ap = arch_print; ap->astr; ap++) { + if (ap->arch == arch) { + if (machine == 0) + return ap->astr; + return (*ap->mach_print)(ap, machine); + } + } + return "UNKNOWN!"; +} + +static char * +prt_num_mach (ap, machine) + struct arch_print *ap; + unsigned long machine; +{ + static char result[20]; + + sprintf(result, "%s:%ld", ap->astr, (long) machine); + return result; +} + +/* Scan a string and attempt to turn it into an archive and machine type + combination. */ + +boolean +bfd_scan_arch_mach (string, archp, machinep) + char *string; + enum bfd_architecture *archp; + unsigned long *machinep; +{ + struct arch_print *ap; + int len; + + /* First look for an architecture, possibly followed by machtype. */ + for (ap = arch_print; ap->astr; ap++) { + if (ap->astr[0] != string[0]) + continue; + len = strlen (ap->astr); + if (!strncmp (ap->astr, string, len)) { + /* We found the architecture, now see about the machine type */ + if (archp) + *archp = ap->arch; + if (string[len] != '\0') { + if (ap->mach_scan (string+len, ap, archp, machinep, 1)) + return true; + } + if (machinep) + *machinep = 0; + return true; + } + } + + /* Couldn't find an architecture -- try for just a machine type */ + for (ap = arch_print; ap->astr; ap++) { + if (ap->mach_scan (string, ap, archp, machinep, 0)) + return true; + } + + return false; +} + +static boolean +scan_num_mach (string, ap, archp, machinep, archspec) + char *string; + struct arch_print *ap; + enum bfd_architecture *archp; + unsigned long *machinep; + int archspec; +{ + enum bfd_architecture arch; + unsigned long machine; + char achar; + + if (archspec) { + + /* Architecture already specified, now go for machine type. */ + if (string[0] != ':') + return false; + /* We'll take any valid number that occupies the entire string */ + if (1 != sscanf (string+1, "%lu%c", &machine, &achar)) + return false; + arch = ap->arch; + + } else { + + /* We couldn't identify an architecture prefix. Perhaps the entire + thing is a machine type. Be a lot picker. */ + if (1 != sscanf (string, "%lu%c", &machine, &achar)) + return false; + switch (machine) { + case 68010: + case 68020: + case 68030: + case 68040: + case 68332: + case 68050: arch = bfd_arch_m68k; break; + case 68000: arch = bfd_arch_m68k; machine = 0; break; + + case 80960: + case 960: arch = bfd_arch_i960; machine = 0; break; + + case 386: + case 80386: arch = bfd_arch_i386; machine = 0; break; + case 486: arch = bfd_arch_i386; break; + + case 29000: arch = bfd_arch_a29k; machine = 0; break; + + case 32016: + case 32032: + case 32132: + case 32232: + case 32332: + case 32432: + case 32532: arch = bfd_arch_ns32k; break; + case 32000: arch = bfd_arch_ns32k; machine = 0; break; + + case 860: + case 80860: arch = bfd_arch_i860; machine = 0; break; + + default: return false; + } + } + + if (archp) + *archp = arch; + if (machinep) + *machinep = machine; + return true; +} + +/* Intel 960 machine variants. */ + +static char * +prt_960_mach (ap, machine) + struct arch_print *ap; + unsigned long machine; +{ + static char result[20]; + char *str; + + switch (machine) { + case bfd_mach_i960_core: str = "core"; break; + case bfd_mach_i960_kb_sb: str = "kb"; break; + case bfd_mach_i960_mc: str = "mc"; break; + case bfd_mach_i960_xa: str = "xa"; break; + case bfd_mach_i960_ca: str = "ca"; break; + case bfd_mach_i960_ka_sa: str = "ka"; break; + default: + return prt_num_mach (ap, machine); + } + sprintf (result, "%s:%s", ap->astr, str); + return result; +} + +static boolean +scan_960_mach (string, ap, archp, machinep, archspec) + char *string; + struct arch_print *ap; + enum bfd_architecture *archp; + unsigned long *machinep; + int archspec; +{ + unsigned long machine; + + if (!archspec) + return false; + if (string[0] != ':') + return false; + string++; + if (string[0] == '\0') + return false; + if (string[0] == 'c' && string[1] == 'o' && string[2] == 'r' && + string[3] == 'e' && string[4] == '\0') + machine = bfd_mach_i960_core; + else if (string[1] == '\0' || string[2] != '\0') /* rest are 2-char */ + return false; + else if (string[0] == 'k' && string[1] == 'b') + machine = bfd_mach_i960_kb_sb; + else if (string[0] == 's' && string[1] == 'b') + machine = bfd_mach_i960_kb_sb; + else if (string[0] == 'm' && string[1] == 'c') + machine = bfd_mach_i960_mc; + else if (string[0] == 'x' && string[1] == 'a') + machine = bfd_mach_i960_xa; + else if (string[0] == 'c' && string[1] == 'a') + machine = bfd_mach_i960_ca; + else if (string[0] == 'k' && string[1] == 'a') + machine = bfd_mach_i960_ka_sa; + else if (string[0] == 's' && string[1] == 'a') + machine = bfd_mach_i960_ka_sa; + else + return false; + + if (archp) + *archp = ap->arch; + if (machinep) + *machinep = machine; + return true; +} + + + +/* Determine whether two BFDs' architectures and machine types are + compatible. Return merged architecture and machine type if nonnull + pointers. */ + +boolean +bfd_arch_compatible (abfd, bbfd, archp, machinep) + bfd *abfd; + bfd *bbfd; + enum bfd_architecture *archp; + unsigned long *machinep; +{ + enum bfd_architecture archa, archb; + unsigned long macha, machb; + int pick_a; + + archa = bfd_get_architecture (abfd); + archb = bfd_get_architecture (bbfd); + macha = bfd_get_machine (abfd); + machb = bfd_get_machine (bbfd); + + if (archb == bfd_arch_unknown) + pick_a = 1; + else if (archa == bfd_arch_unknown) + pick_a = 0; + else if (archa != archb) + return false; /* Not compatible */ + else { + /* Architectures are the same. Check machine types. */ + if (macha == machb) /* Same machine type */ + pick_a = 1; + else if (machb == 0) /* B is default */ + pick_a = 1; + else if (macha == 0) /* A is default */ + pick_a = 0; + else switch (archa) { + /* If particular machine types of one architecture are not + compatible with each other, this is the place to put those tests + (returning false if incompatible). */ + case bfd_arch_i960: + /* The i960 has to distinct subspecies which may not interbreed: + CORE CA + CORE KA KB MC + Any architecture on the same line is compatible, the one on + the right is the least restrictive. + */ + /* So, if either is a ca then the other must be a be core or ca */ + if (macha == bfd_mach_i960_ca) { + if (machb != bfd_mach_i960_ca && + machb != bfd_mach_i960_core) { + return false; + } + pick_a = 1; + } + else if (machb == bfd_mach_i960_ca) { + if (macha != bfd_mach_i960_ca && + macha != bfd_mach_i960_core) { + return false; + } + pick_a = 0; + } + else { + /* This must be from the bottom row, so take the higest */ + pick_a = (macha > machb); + } + + + + break; + + /* For these chips, as far as we care, "lower" numbers are included + by "higher" numbers, e.g. merge 68010 and 68020 into 68020, + 386 and 486 into 486, etc. This will need to change + if&when we care about things like 68332. */ + case bfd_arch_m68k: + case bfd_arch_ns32k: + case bfd_arch_i386: + pick_a = (macha > machb); + break; + + /* By default, pick first file's type, for lack of something better. */ + default: + pick_a = 1; + } + } + + /* Set result based on our pick */ + if (!pick_a) { + archa = archb; + macha = machb; + } + if (archp) + *archp = archa; + if (machinep) + *machinep = macha; + + return true; +} |