1 /* LoongArch opcode support.
2 Copyright (C) 2021-2022 Free Software Foundation, Inc.
3 Contributed by Loongson Ltd.
5 This file is part of the GNU opcodes library.
7 This library 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, or (at your option)
12 It is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; see the file COPYING3. If not,
19 see <http://www.gnu.org/licenses/>. */
22 #include "disassemble.h"
24 #include "opcode/loongarch.h"
25 #include "libiberty.h"
28 static const struct loongarch_opcode
*
29 get_loongarch_opcode_by_binfmt (insn_t insn
)
31 const struct loongarch_opcode
*it
;
32 struct loongarch_ase
*ase
;
34 for (ase
= loongarch_ASEs
; ase
->enabled
; ase
++)
36 if (!*ase
->enabled
|| (ase
->include
&& !*ase
->include
)
37 || (ase
->exclude
&& *ase
->exclude
))
40 if (!ase
->opc_htab_inited
)
42 for (it
= ase
->opcodes
; it
->mask
; it
++)
43 if (!ase
->opc_htab
[LARCH_INSN_OPC (it
->match
)]
45 ase
->opc_htab
[LARCH_INSN_OPC (it
->match
)] = it
;
46 for (i
= 0; i
< 16; i
++)
47 if (!ase
->opc_htab
[i
])
48 ase
->opc_htab
[i
] = it
;
49 ase
->opc_htab_inited
= 1;
52 it
= ase
->opc_htab
[LARCH_INSN_OPC (insn
)];
53 for (; it
->name
; it
++)
54 if ((insn
& it
->mask
) == it
->match
&& it
->mask
55 && !(it
->include
&& !*it
->include
)
56 && !(it
->exclude
&& *it
->exclude
))
62 static const char *const *loongarch_r_disname
= NULL
;
63 static const char *const *loongarch_f_disname
= NULL
;
64 static const char *const *loongarch_c_disname
= NULL
;
65 static const char *const *loongarch_cr_disname
= NULL
;
66 static const char *const *loongarch_v_disname
= NULL
;
67 static const char *const *loongarch_x_disname
= NULL
;
70 set_default_loongarch_dis_options (void)
72 LARCH_opts
.ase_ilp32
= 1;
73 LARCH_opts
.ase_lp64
= 1;
74 LARCH_opts
.ase_sf
= 1;
75 LARCH_opts
.ase_df
= 1;
76 LARCH_opts
.ase_lsx
= 1;
77 LARCH_opts
.ase_lasx
= 1;
79 loongarch_r_disname
= loongarch_r_lp64_name
;
80 loongarch_f_disname
= loongarch_f_lp64_name
;
81 loongarch_c_disname
= loongarch_c_normal_name
;
82 loongarch_cr_disname
= loongarch_cr_normal_name
;
83 loongarch_v_disname
= loongarch_v_normal_name
;
84 loongarch_x_disname
= loongarch_x_normal_name
;
88 parse_loongarch_dis_option (const char *option
)
90 if (strcmp (option
, "numeric") == 0)
92 loongarch_r_disname
= loongarch_r_normal_name
;
93 loongarch_f_disname
= loongarch_f_normal_name
;
99 parse_loongarch_dis_options (const char *opts_in
)
101 set_default_loongarch_dis_options ();
106 char *opts
, *opt
, *opt_end
;
107 opts
= xmalloc (strlen (opts_in
) + 1);
108 strcpy (opts
, opts_in
);
110 for (opt
= opt_end
= opts
; opt_end
!= NULL
; opt
= opt_end
+ 1)
112 if ((opt_end
= strchr (opt
, ',')) != NULL
)
114 if (parse_loongarch_dis_option (opt
) != 0)
122 dis_one_arg (char esc1
, char esc2
, const char *bit_field
,
123 const char *arg ATTRIBUTE_UNUSED
, void *context
)
125 static int need_comma
= 0;
126 struct disassemble_info
*info
= context
;
127 insn_t insn
= *(insn_t
*) info
->private_data
;
133 info
->fprintf_func (info
->stream
, ", ");
135 imm
= loongarch_decode_imm (bit_field
, insn
, 1);
136 u_imm
= loongarch_decode_imm (bit_field
, insn
, 0);
142 info
->fprintf_func (info
->stream
, "%s", loongarch_r_disname
[u_imm
]);
145 info
->fprintf_func (info
->stream
, "%s", loongarch_f_disname
[u_imm
]);
151 info
->fprintf_func (info
->stream
, "%s", loongarch_cr_disname
[u_imm
]);
154 info
->fprintf_func (info
->stream
, "%s", loongarch_c_disname
[u_imm
]);
158 info
->fprintf_func (info
->stream
, "%s", loongarch_v_disname
[u_imm
]);
161 info
->fprintf_func (info
->stream
, "%s", loongarch_x_disname
[u_imm
]);
164 info
->fprintf_func (info
->stream
, "0x%x", u_imm
);
168 info
->fprintf_func (info
->stream
, "%d", imm
);
170 info
->fprintf_func (info
->stream
, "%d(0x%x)", imm
, u_imm
);
174 info
->insn_type
= dis_branch
;
185 disassemble_one (insn_t insn
, struct disassemble_info
*info
)
187 const struct loongarch_opcode
*opc
= get_loongarch_opcode_by_binfmt (insn
);
189 #ifdef LOONGARCH_DEBUG
190 char have_space
[32] = { 0 };
193 const char *t_f
= opc
? opc
->format
: NULL
;
197 while (('a' <= t_f
[0] && t_f
[0] <= 'z')
198 || ('A' <= t_f
[0] && t_f
[0] <= 'Z')
203 i
= strtol (t_f
, &t_f
, 10);
206 i
+= strtol (t_f
, &t_f
, 10);
214 t_f
+= 2; /* '<' '<' */
215 strtol (t_f
, &t_f
, 10);
220 t
= ~((insn_t
) -1 >> 1);
221 for (i
= 31; 0 <= i
; i
--)
224 info
->fprintf_func (info
->stream
, "1");
226 info
->fprintf_func (info
->stream
, "0");
228 info
->fprintf_func (info
->stream
, " ");
231 info
->fprintf_func (info
->stream
, "\t");
236 info
->insn_type
= dis_noninsn
;
237 info
->fprintf_func (info
->stream
, "0x%08x", insn
);
241 info
->insn_type
= dis_nonbranch
;
242 info
->fprintf_func (info
->stream
, "%-12s", opc
->name
);
245 char *fake_args
= xmalloc (strlen (opc
->format
) + 1);
246 const char *fake_arg_strs
[MAX_ARG_NUM_PLUS_2
];
247 strcpy (fake_args
, opc
->format
);
248 if (0 < loongarch_split_args_by_comma (fake_args
, fake_arg_strs
))
249 info
->fprintf_func (info
->stream
, "\t");
250 info
->private_data
= &insn
;
251 loongarch_foreach_args (opc
->format
, fake_arg_strs
, dis_one_arg
, info
);
255 if (info
->insn_type
== dis_branch
|| info
->insn_type
== dis_condbranch
256 /* Someother if we have extra info to print. */)
257 info
->fprintf_func (info
->stream
, "\t#");
259 if (info
->insn_type
== dis_branch
|| info
->insn_type
== dis_condbranch
)
261 info
->fprintf_func (info
->stream
, " ");
262 info
->print_address_func (info
->target
, info
);
267 print_insn_loongarch (bfd_vma memaddr
, struct disassemble_info
*info
)
272 static int not_init_yet
= 1;
275 parse_loongarch_dis_options (info
->disassembler_options
);
279 info
->bytes_per_chunk
= 4;
280 info
->bytes_per_line
= 4;
281 info
->display_endian
= BFD_ENDIAN_LITTLE
;
282 info
->insn_info_valid
= 1;
283 info
->target
= memaddr
;
285 if ((status
= info
->read_memory_func (memaddr
, (bfd_byte
*) &insn
,
286 sizeof (insn
), info
)) != 0)
288 info
->memory_error_func (status
, memaddr
, info
);
289 return -1; /* loongarch_insn_length (0); */
292 disassemble_one (insn
, info
);
294 return loongarch_insn_length (insn
);
298 print_loongarch_disassembler_options (FILE *stream
)
300 fprintf (stream
, _("\n\
301 The following LoongArch disassembler options are supported for use\n\
302 with the -M switch (multiple options should be separated by commas):\n"));
304 fprintf (stream
, _("\n\
305 numeric Print numeric register names, rather than ABI names.\n"));
306 fprintf (stream
, _("\n"));
310 loongarch_parse_dis_options (const char *opts_in
)
312 return parse_loongarch_dis_options (opts_in
);
316 my_print_address_func (bfd_vma addr
, struct disassemble_info
*dinfo
)
318 dinfo
->fprintf_func (dinfo
->stream
, "0x%llx", (long long) addr
);
322 loongarch_disassemble_one (int64_t pc
, insn_t insn
,
323 int (*fprintf_func
) (void *stream
,
324 const char *format
, ...),
327 static struct disassemble_info my_disinfo
=
329 .print_address_func
= my_print_address_func
,
331 static int not_init_yet
= 1;
334 loongarch_parse_dis_options (NULL
);
338 my_disinfo
.fprintf_func
= fprintf_func
;
339 my_disinfo
.stream
= stream
;
340 my_disinfo
.target
= pc
;
341 disassemble_one (insn
, &my_disinfo
);