1 | /* Disassemble SH64 instructions.
|
---|
2 | Copyright 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
|
---|
3 |
|
---|
4 | This program is free software; you can redistribute it and/or modify
|
---|
5 | it under the terms of the GNU General Public License as published by
|
---|
6 | the Free Software Foundation; either version 2 of the License, or
|
---|
7 | (at your option) any later version.
|
---|
8 |
|
---|
9 | This program is distributed in the hope that it will be useful,
|
---|
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
12 | GNU General Public License for more details.
|
---|
13 |
|
---|
14 | You should have received a copy of the GNU General Public License
|
---|
15 | along with this program; if not, write to the Free Software
|
---|
16 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
---|
17 |
|
---|
18 | #include <stdio.h>
|
---|
19 |
|
---|
20 | #include "dis-asm.h"
|
---|
21 | #include "sysdep.h"
|
---|
22 | #include "sh64-opc.h"
|
---|
23 | #include "libiberty.h"
|
---|
24 |
|
---|
25 | /* We need to refer to the ELF header structure. */
|
---|
26 | #include "elf-bfd.h"
|
---|
27 | #include "elf/sh.h"
|
---|
28 | #include "elf32-sh64.h"
|
---|
29 |
|
---|
30 | #define ELF_MODE32_CODE_LABEL_P(SYM) \
|
---|
31 | (((elf_symbol_type *) (SYM))->internal_elf_sym.st_other & STO_SH5_ISA32)
|
---|
32 |
|
---|
33 | #define SAVED_MOVI_R(INFO) \
|
---|
34 | (((struct sh64_disassemble_info *) ((INFO)->private_data))->address_reg)
|
---|
35 |
|
---|
36 | #define SAVED_MOVI_IMM(INFO) \
|
---|
37 | (((struct sh64_disassemble_info *) ((INFO)->private_data))->built_address)
|
---|
38 |
|
---|
39 | struct sh64_disassemble_info
|
---|
40 | {
|
---|
41 | /* When we see a MOVI, we save the register and the value, and merge a
|
---|
42 | subsequent SHORI and display the address, if there is one. */
|
---|
43 | unsigned int address_reg;
|
---|
44 | bfd_signed_vma built_address;
|
---|
45 |
|
---|
46 | /* This is the range decriptor for the current address. It is kept
|
---|
47 | around for the next call. */
|
---|
48 | sh64_elf_crange crange;
|
---|
49 | };
|
---|
50 |
|
---|
51 | /* Each item in the table is a mask to indicate which bits to be set
|
---|
52 | to determine an instruction's operator.
|
---|
53 | The index is as same as the instruction in the opcode table.
|
---|
54 | Note that some archs have this as a field in the opcode table. */
|
---|
55 | static unsigned long *shmedia_opcode_mask_table;
|
---|
56 |
|
---|
57 | static void initialize_shmedia_opcode_mask_table PARAMS ((void));
|
---|
58 | static int print_insn_shmedia PARAMS ((bfd_vma, disassemble_info *));
|
---|
59 | static const char *creg_name PARAMS ((int));
|
---|
60 | static bfd_boolean init_sh64_disasm_info PARAMS ((struct disassemble_info *));
|
---|
61 | static enum sh64_elf_cr_type sh64_get_contents_type_disasm
|
---|
62 | PARAMS ((bfd_vma, struct disassemble_info *));
|
---|
63 |
|
---|
64 | /* Initialize the SH64 opcode mask table for each instruction in SHmedia
|
---|
65 | mode. */
|
---|
66 |
|
---|
67 | static void
|
---|
68 | initialize_shmedia_opcode_mask_table ()
|
---|
69 | {
|
---|
70 | int n_opc;
|
---|
71 | int n;
|
---|
72 |
|
---|
73 | /* Calculate number of opcodes. */
|
---|
74 | for (n_opc = 0; shmedia_table[n_opc].name != NULL; n_opc++)
|
---|
75 | ;
|
---|
76 |
|
---|
77 | shmedia_opcode_mask_table
|
---|
78 | = xmalloc (sizeof (shmedia_opcode_mask_table[0]) * n_opc);
|
---|
79 |
|
---|
80 | for (n = 0; n < n_opc; n++)
|
---|
81 | {
|
---|
82 | int i;
|
---|
83 |
|
---|
84 | unsigned long mask = 0;
|
---|
85 |
|
---|
86 | for (i = 0; shmedia_table[n].arg[i] != A_NONE; i++)
|
---|
87 | {
|
---|
88 | int offset = shmedia_table[n].nibbles[i];
|
---|
89 | int length;
|
---|
90 |
|
---|
91 | switch (shmedia_table[n].arg[i])
|
---|
92 | {
|
---|
93 | case A_GREG_M:
|
---|
94 | case A_GREG_N:
|
---|
95 | case A_GREG_D:
|
---|
96 | case A_CREG_K:
|
---|
97 | case A_CREG_J:
|
---|
98 | case A_FREG_G:
|
---|
99 | case A_FREG_H:
|
---|
100 | case A_FREG_F:
|
---|
101 | case A_DREG_G:
|
---|
102 | case A_DREG_H:
|
---|
103 | case A_DREG_F:
|
---|
104 | case A_FMREG_G:
|
---|
105 | case A_FMREG_H:
|
---|
106 | case A_FMREG_F:
|
---|
107 | case A_FPREG_G:
|
---|
108 | case A_FPREG_H:
|
---|
109 | case A_FPREG_F:
|
---|
110 | case A_FVREG_G:
|
---|
111 | case A_FVREG_H:
|
---|
112 | case A_FVREG_F:
|
---|
113 | case A_REUSE_PREV:
|
---|
114 | length = 6;
|
---|
115 | break;
|
---|
116 |
|
---|
117 | case A_TREG_A:
|
---|
118 | case A_TREG_B:
|
---|
119 | length = 3;
|
---|
120 | break;
|
---|
121 |
|
---|
122 | case A_IMMM:
|
---|
123 | abort ();
|
---|
124 | break;
|
---|
125 |
|
---|
126 | case A_IMMU5:
|
---|
127 | length = 5;
|
---|
128 | break;
|
---|
129 |
|
---|
130 | case A_IMMS6:
|
---|
131 | case A_IMMU6:
|
---|
132 | case A_IMMS6BY32:
|
---|
133 | length = 6;
|
---|
134 | break;
|
---|
135 |
|
---|
136 | case A_IMMS10:
|
---|
137 | case A_IMMS10BY1:
|
---|
138 | case A_IMMS10BY2:
|
---|
139 | case A_IMMS10BY4:
|
---|
140 | case A_IMMS10BY8:
|
---|
141 | length = 10;
|
---|
142 | break;
|
---|
143 |
|
---|
144 | case A_IMMU16:
|
---|
145 | case A_IMMS16:
|
---|
146 | case A_PCIMMS16BY4:
|
---|
147 | case A_PCIMMS16BY4_PT:
|
---|
148 | length = 16;
|
---|
149 | break;
|
---|
150 |
|
---|
151 | default:
|
---|
152 | abort ();
|
---|
153 | length = 0;
|
---|
154 | break;
|
---|
155 | }
|
---|
156 |
|
---|
157 | if (length != 0)
|
---|
158 | mask |= (0xffffffff >> (32 - length)) << offset;
|
---|
159 | }
|
---|
160 | shmedia_opcode_mask_table[n] = 0xffffffff & ~mask;
|
---|
161 | }
|
---|
162 | }
|
---|
163 |
|
---|
164 | /* Get a predefined control-register-name, or return NULL. */
|
---|
165 |
|
---|
166 | const char *
|
---|
167 | creg_name (cregno)
|
---|
168 | int cregno;
|
---|
169 | {
|
---|
170 | const shmedia_creg_info *cregp;
|
---|
171 |
|
---|
172 | /* If control register usage is common enough, change this to search a
|
---|
173 | hash-table. */
|
---|
174 | for (cregp = shmedia_creg_table; cregp->name != NULL; cregp++)
|
---|
175 | {
|
---|
176 | if (cregp->cregno == cregno)
|
---|
177 | return cregp->name;
|
---|
178 | }
|
---|
179 |
|
---|
180 | return NULL;
|
---|
181 | }
|
---|
182 |
|
---|
183 | /* Main function to disassemble SHmedia instructions. */
|
---|
184 |
|
---|
185 | static int
|
---|
186 | print_insn_shmedia (memaddr, info)
|
---|
187 | bfd_vma memaddr;
|
---|
188 | struct disassemble_info *info;
|
---|
189 | {
|
---|
190 | fprintf_ftype fprintf_fn = info->fprintf_func;
|
---|
191 | void *stream = info->stream;
|
---|
192 |
|
---|
193 | unsigned char insn[4];
|
---|
194 | unsigned long instruction;
|
---|
195 | int status;
|
---|
196 | int n;
|
---|
197 | const shmedia_opcode_info *op;
|
---|
198 | int i;
|
---|
199 | unsigned int r = 0;
|
---|
200 | long imm = 0;
|
---|
201 | bfd_vma disp_pc_addr;
|
---|
202 |
|
---|
203 | status = info->read_memory_func (memaddr, insn, 4, info);
|
---|
204 |
|
---|
205 | /* If we can't read four bytes, something is wrong. Display any data we
|
---|
206 | can get as .byte:s. */
|
---|
207 | if (status != 0)
|
---|
208 | {
|
---|
209 | int i;
|
---|
210 |
|
---|
211 | for (i = 0; i < 3; i++)
|
---|
212 | {
|
---|
213 | status = info->read_memory_func (memaddr + i, insn, 1, info);
|
---|
214 | if (status != 0)
|
---|
215 | break;
|
---|
216 | (*fprintf_fn) (stream, "%s0x%02x",
|
---|
217 | i == 0 ? ".byte " : ", ",
|
---|
218 | insn[0]);
|
---|
219 | }
|
---|
220 |
|
---|
221 | return i ? i : -1;
|
---|
222 | }
|
---|
223 |
|
---|
224 | /* Rearrange the bytes to make up an instruction. */
|
---|
225 | if (info->endian == BFD_ENDIAN_LITTLE)
|
---|
226 | instruction = bfd_getl32 (insn);
|
---|
227 | else
|
---|
228 | instruction = bfd_getb32 (insn);
|
---|
229 |
|
---|
230 | /* FIXME: Searching could be implemented using a hash on relevant
|
---|
231 | fields. */
|
---|
232 | for (n = 0, op = shmedia_table;
|
---|
233 | op->name != NULL
|
---|
234 | && ((instruction & shmedia_opcode_mask_table[n]) != op->opcode_base);
|
---|
235 | n++, op++)
|
---|
236 | ;
|
---|
237 |
|
---|
238 | /* FIXME: We should also check register number constraints. */
|
---|
239 | if (op->name == NULL)
|
---|
240 | {
|
---|
241 | fprintf_fn (stream, ".long 0x%08x", instruction);
|
---|
242 | return 4;
|
---|
243 | }
|
---|
244 |
|
---|
245 | fprintf_fn (stream, "%s\t", op->name);
|
---|
246 |
|
---|
247 | for (i = 0; i < 3 && op->arg[i] != A_NONE; i++)
|
---|
248 | {
|
---|
249 | unsigned long temp = instruction >> op->nibbles[i];
|
---|
250 | int by_number = 0;
|
---|
251 |
|
---|
252 | if (i > 0 && op->arg[i] != A_REUSE_PREV)
|
---|
253 | fprintf_fn (stream, ",");
|
---|
254 |
|
---|
255 | switch (op->arg[i])
|
---|
256 | {
|
---|
257 | case A_REUSE_PREV:
|
---|
258 | continue;
|
---|
259 |
|
---|
260 | case A_GREG_M:
|
---|
261 | case A_GREG_N:
|
---|
262 | case A_GREG_D:
|
---|
263 | r = temp & 0x3f;
|
---|
264 | fprintf_fn (stream, "r%d", r);
|
---|
265 | break;
|
---|
266 |
|
---|
267 | case A_FVREG_F:
|
---|
268 | case A_FVREG_G:
|
---|
269 | case A_FVREG_H:
|
---|
270 | r = temp & 0x3f;
|
---|
271 | fprintf_fn (stream, "fv%d", r);
|
---|
272 | break;
|
---|
273 |
|
---|
274 | case A_FPREG_F:
|
---|
275 | case A_FPREG_G:
|
---|
276 | case A_FPREG_H:
|
---|
277 | r = temp & 0x3f;
|
---|
278 | fprintf_fn (stream, "fp%d", r);
|
---|
279 | break;
|
---|
280 |
|
---|
281 | case A_FMREG_F:
|
---|
282 | case A_FMREG_G:
|
---|
283 | case A_FMREG_H:
|
---|
284 | r = temp & 0x3f;
|
---|
285 | fprintf_fn (stream, "mtrx%d", r);
|
---|
286 | break;
|
---|
287 |
|
---|
288 | case A_CREG_K:
|
---|
289 | case A_CREG_J:
|
---|
290 | {
|
---|
291 | const char *name;
|
---|
292 | r = temp & 0x3f;
|
---|
293 |
|
---|
294 | name = creg_name (r);
|
---|
295 |
|
---|
296 | if (name != NULL)
|
---|
297 | fprintf_fn (stream, "%s", name);
|
---|
298 | else
|
---|
299 | fprintf_fn (stream, "cr%d", r);
|
---|
300 | }
|
---|
301 | break;
|
---|
302 |
|
---|
303 | case A_FREG_G:
|
---|
304 | case A_FREG_H:
|
---|
305 | case A_FREG_F:
|
---|
306 | r = temp & 0x3f;
|
---|
307 | fprintf_fn (stream, "fr%d", r);
|
---|
308 | break;
|
---|
309 |
|
---|
310 | case A_DREG_G:
|
---|
311 | case A_DREG_H:
|
---|
312 | case A_DREG_F:
|
---|
313 | r = temp & 0x3f;
|
---|
314 | fprintf_fn (stream, "dr%d", r);
|
---|
315 | break;
|
---|
316 |
|
---|
317 | case A_TREG_A:
|
---|
318 | case A_TREG_B:
|
---|
319 | r = temp & 0x7;
|
---|
320 | fprintf_fn (stream, "tr%d", r);
|
---|
321 | break;
|
---|
322 |
|
---|
323 | /* A signed 6-bit number. */
|
---|
324 | case A_IMMS6:
|
---|
325 | imm = temp & 0x3f;
|
---|
326 | if (imm & (unsigned long) 0x20)
|
---|
327 | imm |= ~(unsigned long) 0x3f;
|
---|
328 | fprintf_fn (stream, "%d", imm);
|
---|
329 | break;
|
---|
330 |
|
---|
331 | /* A signed 6-bit number, multiplied by 32 when used. */
|
---|
332 | case A_IMMS6BY32:
|
---|
333 | imm = temp & 0x3f;
|
---|
334 | if (imm & (unsigned long) 0x20)
|
---|
335 | imm |= ~(unsigned long) 0x3f;
|
---|
336 | fprintf_fn (stream, "%d", imm * 32);
|
---|
337 | break;
|
---|
338 |
|
---|
339 | /* A signed 10-bit number, multiplied by 8 when used. */
|
---|
340 | case A_IMMS10BY8:
|
---|
341 | by_number++;
|
---|
342 | /* Fall through. */
|
---|
343 |
|
---|
344 | /* A signed 10-bit number, multiplied by 4 when used. */
|
---|
345 | case A_IMMS10BY4:
|
---|
346 | by_number++;
|
---|
347 | /* Fall through. */
|
---|
348 |
|
---|
349 | /* A signed 10-bit number, multiplied by 2 when used. */
|
---|
350 | case A_IMMS10BY2:
|
---|
351 | by_number++;
|
---|
352 | /* Fall through. */
|
---|
353 |
|
---|
354 | /* A signed 10-bit number. */
|
---|
355 | case A_IMMS10:
|
---|
356 | case A_IMMS10BY1:
|
---|
357 | imm = temp & 0x3ff;
|
---|
358 | if (imm & (unsigned long) 0x200)
|
---|
359 | imm |= ~(unsigned long) 0x3ff;
|
---|
360 | imm <<= by_number;
|
---|
361 | fprintf_fn (stream, "%d", imm);
|
---|
362 | break;
|
---|
363 |
|
---|
364 | /* A signed 16-bit number. */
|
---|
365 | case A_IMMS16:
|
---|
366 | imm = temp & 0xffff;
|
---|
367 | if (imm & (unsigned long) 0x8000)
|
---|
368 | imm |= ~((unsigned long) 0xffff);
|
---|
369 | fprintf_fn (stream, "%d", imm);
|
---|
370 | break;
|
---|
371 |
|
---|
372 | /* A PC-relative signed 16-bit number, multiplied by 4 when
|
---|
373 | used. */
|
---|
374 | case A_PCIMMS16BY4:
|
---|
375 | imm = temp & 0xffff; /* 16 bits */
|
---|
376 | if (imm & (unsigned long) 0x8000)
|
---|
377 | imm |= ~(unsigned long) 0xffff;
|
---|
378 | imm <<= 2;
|
---|
379 | disp_pc_addr = (bfd_vma) imm + memaddr;
|
---|
380 | (*info->print_address_func) (disp_pc_addr, info);
|
---|
381 | break;
|
---|
382 |
|
---|
383 | /* An unsigned 5-bit number. */
|
---|
384 | case A_IMMU5:
|
---|
385 | imm = temp & 0x1f;
|
---|
386 | fprintf_fn (stream, "%d", imm);
|
---|
387 | break;
|
---|
388 |
|
---|
389 | /* An unsigned 6-bit number. */
|
---|
390 | case A_IMMU6:
|
---|
391 | imm = temp & 0x3f;
|
---|
392 | fprintf_fn (stream, "%d", imm);
|
---|
393 | break;
|
---|
394 |
|
---|
395 | /* An unsigned 16-bit number. */
|
---|
396 | case A_IMMU16:
|
---|
397 | imm = temp & 0xffff;
|
---|
398 | fprintf_fn (stream, "%d", imm);
|
---|
399 | break;
|
---|
400 |
|
---|
401 | default:
|
---|
402 | abort ();
|
---|
403 | break;
|
---|
404 | }
|
---|
405 | }
|
---|
406 |
|
---|
407 | /* FIXME: Looks like 32-bit values only are handled.
|
---|
408 | FIXME: PC-relative numbers aren't handled correctly. */
|
---|
409 | if (op->opcode_base == (unsigned long) SHMEDIA_SHORI_OPC
|
---|
410 | && SAVED_MOVI_R (info) == r)
|
---|
411 | {
|
---|
412 | asection *section = info->section;
|
---|
413 |
|
---|
414 | /* Most callers do not set the section field correctly yet. Revert
|
---|
415 | to getting the section from symbols, if any. */
|
---|
416 | if (section == NULL
|
---|
417 | && info->symbols != NULL
|
---|
418 | && bfd_asymbol_flavour (info->symbols[0]) == bfd_target_elf_flavour
|
---|
419 | && ! bfd_is_und_section (bfd_get_section (info->symbols[0]))
|
---|
420 | && ! bfd_is_abs_section (bfd_get_section (info->symbols[0])))
|
---|
421 | section = bfd_get_section (info->symbols[0]);
|
---|
422 |
|
---|
423 | /* Only guess addresses when the contents of this section is fully
|
---|
424 | relocated. Otherwise, the value will be zero or perhaps even
|
---|
425 | bogus. */
|
---|
426 | if (section == NULL
|
---|
427 | || section->owner == NULL
|
---|
428 | || elf_elfheader (section->owner)->e_type == ET_EXEC)
|
---|
429 | {
|
---|
430 | bfd_signed_vma shori_addr;
|
---|
431 |
|
---|
432 | shori_addr = SAVED_MOVI_IMM (info) << 16;
|
---|
433 | shori_addr |= imm;
|
---|
434 |
|
---|
435 | fprintf_fn (stream, "\t! 0x");
|
---|
436 | (*info->print_address_func) (shori_addr, info);
|
---|
437 | }
|
---|
438 | }
|
---|
439 |
|
---|
440 | if (op->opcode_base == SHMEDIA_MOVI_OPC)
|
---|
441 | {
|
---|
442 | SAVED_MOVI_IMM (info) = imm;
|
---|
443 | SAVED_MOVI_R (info) = r;
|
---|
444 | }
|
---|
445 | else
|
---|
446 | {
|
---|
447 | SAVED_MOVI_IMM (info) = 0;
|
---|
448 | SAVED_MOVI_R (info) = 255;
|
---|
449 | }
|
---|
450 |
|
---|
451 | return 4;
|
---|
452 | }
|
---|
453 |
|
---|
454 | /* Check the type of contents about to be disassembled. This is like
|
---|
455 | sh64_get_contents_type (which may be called from here), except that it
|
---|
456 | takes the same arguments as print_insn_* and does what can be done if
|
---|
457 | no section is available. */
|
---|
458 |
|
---|
459 | static enum sh64_elf_cr_type
|
---|
460 | sh64_get_contents_type_disasm (memaddr, info)
|
---|
461 | bfd_vma memaddr;
|
---|
462 | struct disassemble_info *info;
|
---|
463 | {
|
---|
464 | struct sh64_disassemble_info *sh64_infop = info->private_data;
|
---|
465 |
|
---|
466 | /* Perhaps we have a region from a previous probe and it still counts
|
---|
467 | for this address? */
|
---|
468 | if (sh64_infop->crange.cr_type != CRT_NONE
|
---|
469 | && memaddr >= sh64_infop->crange.cr_addr
|
---|
470 | && memaddr < sh64_infop->crange.cr_addr + sh64_infop->crange.cr_size)
|
---|
471 | return sh64_infop->crange.cr_type;
|
---|
472 |
|
---|
473 | /* If we have a section, try and use it. */
|
---|
474 | if (info->section
|
---|
475 | && bfd_get_flavour (info->section->owner) == bfd_target_elf_flavour)
|
---|
476 | {
|
---|
477 | enum sh64_elf_cr_type cr_type
|
---|
478 | = sh64_get_contents_type (info->section, memaddr,
|
---|
479 | &sh64_infop->crange);
|
---|
480 |
|
---|
481 | if (cr_type != CRT_NONE)
|
---|
482 | return cr_type;
|
---|
483 | }
|
---|
484 |
|
---|
485 | /* If we have symbols, we can try and get at a section from *that*. */
|
---|
486 | if (info->symbols != NULL
|
---|
487 | && bfd_asymbol_flavour (info->symbols[0]) == bfd_target_elf_flavour
|
---|
488 | && ! bfd_is_und_section (bfd_get_section (info->symbols[0]))
|
---|
489 | && ! bfd_is_abs_section (bfd_get_section (info->symbols[0])))
|
---|
490 | {
|
---|
491 | enum sh64_elf_cr_type cr_type
|
---|
492 | = sh64_get_contents_type (bfd_get_section (info->symbols[0]),
|
---|
493 | memaddr, &sh64_infop->crange);
|
---|
494 |
|
---|
495 | if (cr_type != CRT_NONE)
|
---|
496 | return cr_type;
|
---|
497 | }
|
---|
498 |
|
---|
499 | /* We can make a reasonable guess based on the st_other field of a
|
---|
500 | symbol; for a BranchTarget this is marked as STO_SH5_ISA32 and then
|
---|
501 | it's most probably code there. */
|
---|
502 | if (info->symbols
|
---|
503 | && bfd_asymbol_flavour (info->symbols[0]) == bfd_target_elf_flavour
|
---|
504 | && elf_symbol_from (bfd_asymbol_bfd (info->symbols[0]),
|
---|
505 | info->symbols[0])->internal_elf_sym.st_other
|
---|
506 | == STO_SH5_ISA32)
|
---|
507 | return CRT_SH5_ISA32;
|
---|
508 |
|
---|
509 | /* If all else fails, guess this is code and guess on the low bit set. */
|
---|
510 | return (memaddr & 1) == 1 ? CRT_SH5_ISA32 : CRT_SH5_ISA16;
|
---|
511 | }
|
---|
512 |
|
---|
513 | /* Initialize static and dynamic disassembly state. */
|
---|
514 |
|
---|
515 | static bfd_boolean
|
---|
516 | init_sh64_disasm_info (info)
|
---|
517 | struct disassemble_info *info;
|
---|
518 | {
|
---|
519 | struct sh64_disassemble_info *sh64_infop
|
---|
520 | = calloc (sizeof (*sh64_infop), 1);
|
---|
521 |
|
---|
522 | if (sh64_infop == NULL)
|
---|
523 | return FALSE;
|
---|
524 |
|
---|
525 | info->private_data = sh64_infop;
|
---|
526 |
|
---|
527 | SAVED_MOVI_IMM (info) = 0;
|
---|
528 | SAVED_MOVI_R (info) = 255;
|
---|
529 |
|
---|
530 | if (shmedia_opcode_mask_table == NULL)
|
---|
531 | initialize_shmedia_opcode_mask_table ();
|
---|
532 |
|
---|
533 | return TRUE;
|
---|
534 | }
|
---|
535 |
|
---|
536 | /* Main entry to disassemble SHmedia instructions, given an endian set in
|
---|
537 | INFO. Note that the simulator uses this as the main entry and does not
|
---|
538 | use any of the functions further below. */
|
---|
539 |
|
---|
540 | int
|
---|
541 | print_insn_sh64x_media (memaddr, info)
|
---|
542 | bfd_vma memaddr;
|
---|
543 | struct disassemble_info *info;
|
---|
544 | {
|
---|
545 | if (info->private_data == NULL && ! init_sh64_disasm_info (info))
|
---|
546 | return -1;
|
---|
547 |
|
---|
548 | /* Make reasonable output. */
|
---|
549 | info->bytes_per_line = 4;
|
---|
550 | info->bytes_per_chunk = 4;
|
---|
551 |
|
---|
552 | return print_insn_shmedia (memaddr, info);
|
---|
553 | }
|
---|
554 |
|
---|
555 | /* Main entry to disassemble SHmedia insns.
|
---|
556 | If we see an SHcompact instruction, return -2. */
|
---|
557 |
|
---|
558 | int
|
---|
559 | print_insn_sh64 (memaddr, info)
|
---|
560 | bfd_vma memaddr;
|
---|
561 | struct disassemble_info *info;
|
---|
562 | {
|
---|
563 | enum bfd_endian endian = info->endian;
|
---|
564 | enum sh64_elf_cr_type cr_type;
|
---|
565 |
|
---|
566 | if (info->private_data == NULL && ! init_sh64_disasm_info (info))
|
---|
567 | return -1;
|
---|
568 |
|
---|
569 | cr_type = sh64_get_contents_type_disasm (memaddr, info);
|
---|
570 | if (cr_type != CRT_SH5_ISA16)
|
---|
571 | {
|
---|
572 | int length = 4 - (memaddr % 4);
|
---|
573 | info->display_endian = endian;
|
---|
574 |
|
---|
575 | /* If we got an uneven address to indicate SHmedia, adjust it. */
|
---|
576 | if (cr_type == CRT_SH5_ISA32 && length == 3)
|
---|
577 | memaddr--, length = 4;
|
---|
578 |
|
---|
579 | /* Only disassemble on four-byte boundaries. Addresses that are not
|
---|
580 | a multiple of four can happen after a data region. */
|
---|
581 | if (cr_type == CRT_SH5_ISA32 && length == 4)
|
---|
582 | return print_insn_sh64x_media (memaddr, info);
|
---|
583 |
|
---|
584 | /* We get CRT_DATA *only* for data regions in a mixed-contents
|
---|
585 | section. For sections with data only, we get indication of one
|
---|
586 | of the ISA:s. You may think that we shouldn't disassemble
|
---|
587 | section with only data if we can figure that out. However, the
|
---|
588 | disassembly function is by default not called for data-only
|
---|
589 | sections, so if the user explicitly specified disassembly of a
|
---|
590 | data section, that's what we should do. */
|
---|
591 | if (cr_type == CRT_DATA || length != 4)
|
---|
592 | {
|
---|
593 | int status;
|
---|
594 | unsigned char data[4];
|
---|
595 | struct sh64_disassemble_info *sh64_infop = info->private_data;
|
---|
596 |
|
---|
597 | if (length == 4
|
---|
598 | && sh64_infop->crange.cr_type != CRT_NONE
|
---|
599 | && memaddr >= sh64_infop->crange.cr_addr
|
---|
600 | && memaddr < (sh64_infop->crange.cr_addr
|
---|
601 | + sh64_infop->crange.cr_size))
|
---|
602 | length
|
---|
603 | = (sh64_infop->crange.cr_addr
|
---|
604 | + sh64_infop->crange.cr_size - memaddr);
|
---|
605 |
|
---|
606 | status
|
---|
607 | = (*info->read_memory_func) (memaddr, data,
|
---|
608 | length >= 4 ? 4 : length, info);
|
---|
609 |
|
---|
610 | if (status == 0 && length >= 4)
|
---|
611 | {
|
---|
612 | (*info->fprintf_func) (info->stream, ".long 0x%08lx",
|
---|
613 | endian == BFD_ENDIAN_BIG
|
---|
614 | ? (long) (bfd_getb32 (data))
|
---|
615 | : (long) (bfd_getl32 (data)));
|
---|
616 | return 4;
|
---|
617 | }
|
---|
618 | else
|
---|
619 | {
|
---|
620 | int i;
|
---|
621 |
|
---|
622 | for (i = 0; i < length; i++)
|
---|
623 | {
|
---|
624 | status = info->read_memory_func (memaddr + i, data, 1, info);
|
---|
625 | if (status != 0)
|
---|
626 | break;
|
---|
627 | (*info->fprintf_func) (info->stream, "%s0x%02x",
|
---|
628 | i == 0 ? ".byte " : ", ",
|
---|
629 | data[0]);
|
---|
630 | }
|
---|
631 |
|
---|
632 | return i ? i : -1;
|
---|
633 | }
|
---|
634 | }
|
---|
635 | }
|
---|
636 |
|
---|
637 | /* SH1 .. SH4 instruction, let caller handle it. */
|
---|
638 | return -2;
|
---|
639 | }
|
---|