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