1 /* SuperH SH64-specific support for 32-bit ELF 2 Copyright 2000, 2001, 2002, 2003 Free Software Foundation, Inc. 3 4 This file is part of BFD, the Binary File Descriptor library. 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 19 20 #define SH64_ELF 21 22 #include "bfd.h" 23 #include "sysdep.h" 24 #include "libbfd.h" 25 #include "elf-bfd.h" 26 #include "elf/sh.h" 27 #include "elf32-sh64.h" 28 #include "../opcodes/sh64-opc.h" 29 30 static bfd_boolean sh64_address_in_cranges 31 (asection *cranges, bfd_vma, sh64_elf_crange *); 32 33 /* Ordering functions of a crange, for the qsort and bsearch calls and for 34 different endianness. */ 35 36 int 37 _bfd_sh64_crange_qsort_cmpb (const void *p1, const void *p2) 38 { 39 bfd_vma a1 = bfd_getb32 (p1); 40 bfd_vma a2 = bfd_getb32 (p2); 41 42 /* Preserve order if there's ambiguous contents. */ 43 if (a1 == a2) 44 return (char *) p1 - (char *) p2; 45 46 return a1 - a2; 47 } 48 49 int 50 _bfd_sh64_crange_qsort_cmpl (const void *p1, const void *p2) 51 { 52 bfd_vma a1 = (bfd_vma) bfd_getl32 (p1); 53 bfd_vma a2 = (bfd_vma) bfd_getl32 (p2); 54 55 /* Preserve order if there's ambiguous contents. */ 56 if (a1 == a2) 57 return (char *) p1 - (char *) p2; 58 59 return a1 - a2; 60 } 61 62 int 63 _bfd_sh64_crange_bsearch_cmpb (const void *p1, const void *p2) 64 { 65 bfd_vma a1 = *(bfd_vma *) p1; 66 bfd_vma a2 = (bfd_vma) bfd_getb32 (p2); 67 bfd_size_type size 68 = (bfd_size_type) bfd_getb32 (SH64_CRANGE_CR_SIZE_OFFSET + (char *) p2); 69 70 if (a1 >= a2 + size) 71 return 1; 72 if (a1 < a2) 73 return -1; 74 return 0; 75 } 76 77 int 78 _bfd_sh64_crange_bsearch_cmpl (const void *p1, const void *p2) 79 { 80 bfd_vma a1 = *(bfd_vma *) p1; 81 bfd_vma a2 = (bfd_vma) bfd_getl32 (p2); 82 bfd_size_type size 83 = (bfd_size_type) bfd_getl32 (SH64_CRANGE_CR_SIZE_OFFSET + (char *) p2); 84 85 if (a1 >= a2 + size) 86 return 1; 87 if (a1 < a2) 88 return -1; 89 return 0; 90 } 91 92 /* Check whether a specific address is specified within a .cranges 93 section. Return FALSE if not found, and TRUE if found, and the region 94 filled into RANGEP if non-NULL. */ 95 96 static bfd_boolean 97 sh64_address_in_cranges (asection *cranges, bfd_vma addr, 98 sh64_elf_crange *rangep) 99 { 100 bfd_byte *cranges_contents; 101 bfd_byte *found_rangep; 102 bfd_size_type cranges_size = bfd_section_size (cranges->owner, cranges); 103 104 /* If the size is not a multiple of the cranges entry size, then 105 something is badly wrong. */ 106 if ((cranges_size % SH64_CRANGE_SIZE) != 0) 107 return FALSE; 108 109 /* If this section has relocations, then we can't do anything sane. */ 110 if (bfd_get_section_flags (cranges->owner, cranges) & SEC_RELOC) 111 return FALSE; 112 113 /* Has some kind soul (or previous call) left processed, sorted contents 114 for us? */ 115 if ((bfd_get_section_flags (cranges->owner, cranges) & SEC_IN_MEMORY) 116 && elf_section_data (cranges)->this_hdr.sh_type == SHT_SH5_CR_SORTED) 117 cranges_contents = cranges->contents; 118 else 119 { 120 cranges_contents 121 = bfd_malloc (cranges->_cooked_size != 0 122 ? cranges->_cooked_size : cranges->_raw_size); 123 if (cranges_contents == NULL) 124 return FALSE; 125 126 if (! bfd_get_section_contents (cranges->owner, cranges, 127 cranges_contents, (file_ptr) 0, 128 cranges_size)) 129 goto error_return; 130 131 /* Is it sorted? */ 132 if (elf_section_data (cranges)->this_hdr.sh_type 133 != SHT_SH5_CR_SORTED) 134 /* Nope. Lets sort it. */ 135 qsort (cranges_contents, cranges_size / SH64_CRANGE_SIZE, 136 SH64_CRANGE_SIZE, 137 bfd_big_endian (cranges->owner) 138 ? _bfd_sh64_crange_qsort_cmpb : _bfd_sh64_crange_qsort_cmpl); 139 140 /* Let's keep it around. */ 141 cranges->contents = cranges_contents; 142 bfd_set_section_flags (cranges->owner, cranges, 143 bfd_get_section_flags (cranges->owner, cranges) 144 | SEC_IN_MEMORY); 145 146 /* It's sorted now. */ 147 elf_section_data (cranges)->this_hdr.sh_type = SHT_SH5_CR_SORTED; 148 } 149 150 /* Try and find a matching range. */ 151 found_rangep 152 = bsearch (&addr, cranges_contents, cranges_size / SH64_CRANGE_SIZE, 153 SH64_CRANGE_SIZE, 154 bfd_big_endian (cranges->owner) 155 ? _bfd_sh64_crange_bsearch_cmpb 156 : _bfd_sh64_crange_bsearch_cmpl); 157 158 /* Fill in a few return values if we found a matching range. */ 159 if (found_rangep) 160 { 161 enum sh64_elf_cr_type cr_type 162 = bfd_get_16 (cranges->owner, 163 SH64_CRANGE_CR_TYPE_OFFSET + found_rangep); 164 bfd_vma cr_addr 165 = bfd_get_32 (cranges->owner, 166 SH64_CRANGE_CR_ADDR_OFFSET 167 + (char *) found_rangep); 168 bfd_size_type cr_size 169 = bfd_get_32 (cranges->owner, 170 SH64_CRANGE_CR_SIZE_OFFSET 171 + (char *) found_rangep); 172 173 rangep->cr_addr = cr_addr; 174 rangep->cr_size = cr_size; 175 rangep->cr_type = cr_type; 176 177 return TRUE; 178 } 179 180 /* There is a .cranges section, but it does not have a descriptor 181 matching this address. */ 182 return FALSE; 183 184 error_return: 185 free (cranges_contents); 186 return FALSE; 187 } 188 189 /* Determine what ADDR points to in SEC, and fill in a range descriptor in 190 *RANGEP if it's non-NULL. */ 191 192 enum sh64_elf_cr_type 193 sh64_get_contents_type (asection *sec, bfd_vma addr, sh64_elf_crange *rangep) 194 { 195 asection *cranges; 196 197 /* Fill in the range with the boundaries of the section as a default. */ 198 if (bfd_get_flavour (sec->owner) == bfd_target_elf_flavour 199 && elf_elfheader (sec->owner)->e_type == ET_EXEC) 200 { 201 rangep->cr_addr = bfd_get_section_vma (sec->owner, sec); 202 rangep->cr_size = bfd_section_size (sec->owner, sec); 203 rangep->cr_type = CRT_NONE; 204 } 205 else 206 return FALSE; 207 208 /* If none of the pertinent bits are set, then it's a SHcompact (or at 209 least not SHmedia). */ 210 if ((elf_section_data (sec)->this_hdr.sh_flags 211 & (SHF_SH5_ISA32 | SHF_SH5_ISA32_MIXED)) == 0) 212 { 213 enum sh64_elf_cr_type cr_type 214 = ((bfd_get_section_flags (sec->owner, sec) & SEC_CODE) != 0 215 ? CRT_SH5_ISA16 : CRT_DATA); 216 rangep->cr_type = cr_type; 217 return cr_type; 218 } 219 220 /* If only the SHF_SH5_ISA32 bit is set, then we have SHmedia. */ 221 if ((elf_section_data (sec)->this_hdr.sh_flags 222 & (SHF_SH5_ISA32 | SHF_SH5_ISA32_MIXED)) == SHF_SH5_ISA32) 223 { 224 rangep->cr_type = CRT_SH5_ISA32; 225 return CRT_SH5_ISA32; 226 } 227 228 /* Otherwise, we have to look up the .cranges section. */ 229 cranges = bfd_get_section_by_name (sec->owner, SH64_CRANGES_SECTION_NAME); 230 231 if (cranges == NULL) 232 /* A mixed section but there's no .cranges section. This is probably 233 bad input; it does not comply to specs. */ 234 return CRT_NONE; 235 236 /* If this call fails, we will still have CRT_NONE in rangep->cr_type 237 and that will be suitable to return. */ 238 sh64_address_in_cranges (cranges, addr, rangep); 239 240 return rangep->cr_type; 241 } 242 243 /* This is a simpler exported interface for the benefit of gdb et al. */ 244 245 bfd_boolean 246 sh64_address_is_shmedia (asection *sec, bfd_vma addr) 247 { 248 sh64_elf_crange dummy; 249 return sh64_get_contents_type (sec, addr, &dummy) == CRT_SH5_ISA32; 250 } 251