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