/* ARC target-dependent stuff. Extension structure access functions Copyright 1995, 1997, 2000, 2001, 2004, 2005, 2007, 2009 Free Software Foundation, Inc. This file is part of libopcodes. This library 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 3, or (at your option) any later version. It 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 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ #include "sysdep.h" #include <stdlib.h> #include <stdio.h> #include "bfd.h" #include "arc-ext.h" #include "libiberty.h" /* Extension structure */ static struct arcExtMap arc_extension_map; /* Get the name of an extension instruction. */ const char * arcExtMap_instName(int opcode, int minor, int *flags) { if (opcode == 3) { /* FIXME: ??? need to also check 0/1/2 in bit0 for (3f) brk/sleep/swi */ if (minor < 0x09 || minor == 0x3f) return 0; else opcode = 0x1f - 0x10 + minor - 0x09 + 1; } else if (opcode < 0x10) return 0; else opcode -= 0x10; if (!arc_extension_map.instructions[opcode]) return 0; *flags = arc_extension_map.instructions[opcode]->flags; return arc_extension_map.instructions[opcode]->name; } /* Get the name of an extension core register. */ const char * arcExtMap_coreRegName(int value) { if (value < 32) return 0; return arc_extension_map.coreRegisters[value-32]; } /* Get the name of an extension condition code. */ const char * arcExtMap_condCodeName(int value) { if (value < 16) return 0; return arc_extension_map.condCodes[value-16]; } /* Get the name of an extension aux register. */ const char * arcExtMap_auxRegName(long address) { /* walk the list of aux reg names and find the name */ struct ExtAuxRegister *r; for (r = arc_extension_map.auxRegisters; r; r = r->next) { if (r->address == address) return (const char *) r->name; } return 0; } /* Recursively free auxilliary register strcture pointers until the list is empty. */ static void clean_aux_registers(struct ExtAuxRegister *r) { if (r -> next) { clean_aux_registers( r->next); free(r -> name); free(r -> next); r ->next = NULL; } else free(r -> name); } /* Free memory that has been allocated for the extensions. */ static void cleanup_ext_map(void) { struct ExtAuxRegister *r; struct ExtInstruction *insn; int i; /* clean aux reg structure */ r = arc_extension_map.auxRegisters; if (r) { (clean_aux_registers(r)); free(r); } /* clean instructions */ for (i = 0; i < NUM_EXT_INST; i++) { insn = arc_extension_map.instructions[i]; if (insn) free(insn->name); } /* clean core reg struct */ for (i = 0; i < NUM_EXT_CORE; i++) { if (arc_extension_map.coreRegisters[i]) free(arc_extension_map.coreRegisters[i]); } for (i = 0; i < NUM_EXT_COND; i++) { if (arc_extension_map.condCodes[i]) free(arc_extension_map.condCodes[i]); } memset(&arc_extension_map, 0, sizeof(struct arcExtMap)); } int arcExtMap_add(void *base, unsigned long length) { unsigned char *block = (unsigned char *) base; unsigned char *p = (unsigned char *) block; /* Clean up and reset everything if needed. */ cleanup_ext_map(); while (p && p < (block + length)) { /* p[0] == length of record p[1] == type of record For instructions: p[2] = opcode p[3] = minor opcode (if opcode == 3) p[4] = flags p[5]+ = name For core regs and condition codes: p[2] = value p[3]+ = name For aux regs: p[2..5] = value p[6]+ = name (value is p[2]<<24|p[3]<<16|p[4]<<8|p[5]) */ if (p[0] == 0) return -1; switch (p[1]) { case EXT_INSTRUCTION: { char opcode = p[2]; char minor = p[3]; char * insn_name = (char *) xmalloc(( (int)*p-5) * sizeof(char)); struct ExtInstruction * insn = (struct ExtInstruction *) xmalloc(sizeof(struct ExtInstruction)); if (opcode==3) opcode = 0x1f - 0x10 + minor - 0x09 + 1; else opcode -= 0x10; insn -> flags = (char) *(p+4); strcpy (insn_name, (char *) (p+5)); insn -> name = insn_name; arc_extension_map.instructions[(int) opcode] = insn; } break; case EXT_CORE_REGISTER: { char * core_name = (char *) xmalloc(((int)*p-3) * sizeof(char)); strcpy(core_name, (char *) (p+3)); arc_extension_map.coreRegisters[p[2]-32] = core_name; } break; case EXT_COND_CODE: { char * cc_name = (char *) xmalloc( ((int)*p-3) * sizeof(char)); strcpy(cc_name, (char *) (p+3)); arc_extension_map.condCodes[p[2]-16] = cc_name; } break; case EXT_AUX_REGISTER: { /* trickier -- need to store linked list to these */ struct ExtAuxRegister *newAuxRegister = (struct ExtAuxRegister *)malloc(sizeof(struct ExtAuxRegister)); char * aux_name = (char *) xmalloc ( ((int)*p-6) * sizeof(char)); strcpy (aux_name, (char *) (p+6)); newAuxRegister->name = aux_name; newAuxRegister->address = p[2]<<24 | p[3]<<16 | p[4]<<8 | p[5]; newAuxRegister->next = arc_extension_map.auxRegisters; arc_extension_map.auxRegisters = newAuxRegister; } break; default: return -1; } p += p[0]; /* move to next record */ } return 0; } /* Load hw extension descibed in .extArcMap ELF section. */ void build_ARC_extmap (text_bfd) bfd *text_bfd; { char *arcExtMap; bfd_size_type count; asection *p; for (p = text_bfd->sections; p != NULL; p = p->next) if (!strcmp (p->name, ".arcextmap")) { count = bfd_get_section_size (p); arcExtMap = (char *) xmalloc (count); if (bfd_get_section_contents (text_bfd, p, (PTR) arcExtMap, 0, count)) { arcExtMap_add ((PTR) arcExtMap, count); break; } free ((PTR) arcExtMap); } }