arc-dis.c revision 1.9 1 1.1 christos /* Instruction printing code for the ARC.
2 1.9 christos Copyright (C) 1994-2020 Free Software Foundation, Inc.
3 1.6 christos
4 1.6 christos Contributed by Claudiu Zissulescu (claziss (at) synopsys.com)
5 1.1 christos
6 1.1 christos This file is part of libopcodes.
7 1.1 christos
8 1.1 christos This library is free software; you can redistribute it and/or modify
9 1.1 christos it under the terms of the GNU General Public License as published by
10 1.1 christos the Free Software Foundation; either version 3, or (at your option)
11 1.1 christos any later version.
12 1.1 christos
13 1.1 christos It is distributed in the hope that it will be useful, but WITHOUT
14 1.1 christos ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 1.1 christos or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 1.1 christos License for more details.
17 1.1 christos
18 1.1 christos You should have received a copy of the GNU General Public License
19 1.1 christos along with this program; if not, write to the Free Software
20 1.1 christos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21 1.1 christos MA 02110-1301, USA. */
22 1.1 christos
23 1.1 christos #include "sysdep.h"
24 1.6 christos #include <stdio.h>
25 1.6 christos #include <assert.h>
26 1.1 christos #include "dis-asm.h"
27 1.1 christos #include "opcode/arc.h"
28 1.6 christos #include "elf/arc.h"
29 1.6 christos #include "arc-dis.h"
30 1.6 christos #include "arc-ext.h"
31 1.1 christos #include "elf-bfd.h"
32 1.6 christos #include "libiberty.h"
33 1.1 christos #include "opintl.h"
34 1.1 christos
35 1.6 christos /* Structure used to iterate over, and extract the values for, operands of
36 1.6 christos an opcode. */
37 1.6 christos
38 1.6 christos struct arc_operand_iterator
39 1.6 christos {
40 1.7 christos /* The complete instruction value to extract operands from. */
41 1.7 christos unsigned long long insn;
42 1.7 christos
43 1.7 christos /* The LIMM if this is being tracked separately. This field is only
44 1.7 christos valid if we find the LIMM operand in the operand list. */
45 1.7 christos unsigned limm;
46 1.7 christos
47 1.7 christos /* The opcode this iterator is operating on. */
48 1.7 christos const struct arc_opcode *opcode;
49 1.7 christos
50 1.7 christos /* The index into the opcodes operand index list. */
51 1.7 christos const unsigned char *opidx;
52 1.7 christos };
53 1.7 christos
54 1.7 christos /* A private data used by ARC decoder. */
55 1.7 christos struct arc_disassemble_info
56 1.7 christos {
57 1.7 christos /* The current disassembled arc opcode. */
58 1.7 christos const struct arc_opcode *opcode;
59 1.7 christos
60 1.7 christos /* Instruction length w/o limm field. */
61 1.7 christos unsigned insn_len;
62 1.7 christos
63 1.7 christos /* TRUE if we have limm. */
64 1.7 christos bfd_boolean limm_p;
65 1.6 christos
66 1.7 christos /* LIMM value, if exists. */
67 1.7 christos unsigned limm;
68 1.6 christos
69 1.7 christos /* Condition code, if exists. */
70 1.7 christos unsigned condition_code;
71 1.6 christos
72 1.7 christos /* Writeback mode. */
73 1.7 christos unsigned writeback_mode;
74 1.6 christos
75 1.7 christos /* Number of operands. */
76 1.7 christos unsigned operands_count;
77 1.6 christos
78 1.7 christos struct arc_insn_operand operands[MAX_INSN_ARGS];
79 1.6 christos };
80 1.6 christos
81 1.6 christos /* Globals variables. */
82 1.6 christos
83 1.6 christos static const char * const regnames[64] =
84 1.6 christos {
85 1.6 christos "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
86 1.6 christos "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
87 1.6 christos "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
88 1.6 christos "r24", "r25", "gp", "fp", "sp", "ilink", "r30", "blink",
89 1.6 christos
90 1.6 christos "r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39",
91 1.6 christos "r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47",
92 1.6 christos "r48", "r49", "r50", "r51", "r52", "r53", "r54", "r55",
93 1.9 christos "r56", "r57", "r58", "r59", "lp_count", "reserved", "LIMM", "pcl"
94 1.6 christos };
95 1.6 christos
96 1.6 christos static const char * const addrtypenames[ARC_NUM_ADDRTYPES] =
97 1.6 christos {
98 1.6 christos "bd", "jid", "lbd", "mbd", "sd", "sm", "xa", "xd",
99 1.6 christos "cd", "cbd", "cjid", "clbd", "cm", "csd", "cxa", "cxd"
100 1.6 christos };
101 1.6 christos
102 1.6 christos static int addrtypenames_max = ARC_NUM_ADDRTYPES - 1;
103 1.1 christos
104 1.6 christos static const char * const addrtypeunknown = "unknown";
105 1.1 christos
106 1.6 christos /* This structure keeps track which instruction class(es)
107 1.6 christos should be ignored durring disassembling. */
108 1.1 christos
109 1.6 christos typedef struct skipclass
110 1.1 christos {
111 1.6 christos insn_class_t insn_class;
112 1.6 christos insn_subclass_t subclass;
113 1.6 christos struct skipclass *nxt;
114 1.6 christos } skipclass_t, *linkclass;
115 1.6 christos
116 1.6 christos /* Intial classes of instructions to be consider first when
117 1.6 christos disassembling. */
118 1.6 christos static linkclass decodelist = NULL;
119 1.6 christos
120 1.8 christos /* ISA mask value enforced via disassembler info options. ARC_OPCODE_NONE
121 1.8 christos value means that no CPU is enforced. */
122 1.8 christos
123 1.8 christos static unsigned enforced_isa_mask = ARC_OPCODE_NONE;
124 1.8 christos
125 1.8 christos /* True if we want to print using only hex numbers. */
126 1.8 christos static bfd_boolean print_hex = FALSE;
127 1.8 christos
128 1.6 christos /* Macros section. */
129 1.6 christos
130 1.6 christos #ifdef DEBUG
131 1.6 christos # define pr_debug(fmt, args...) fprintf (stderr, fmt, ##args)
132 1.6 christos #else
133 1.6 christos # define pr_debug(fmt, args...)
134 1.6 christos #endif
135 1.6 christos
136 1.6 christos #define ARRANGE_ENDIAN(info, buf) \
137 1.6 christos (info->endian == BFD_ENDIAN_LITTLE ? bfd_getm32 (bfd_getl32 (buf)) \
138 1.6 christos : bfd_getb32 (buf))
139 1.1 christos
140 1.9 christos #define BITS(word,s,e) (((word) >> (s)) & ((1ull << ((e) - (s)) << 1) - 1))
141 1.7 christos #define OPCODE_32BIT_INSN(word) (BITS ((word), 27, 31))
142 1.1 christos
143 1.6 christos /* Functions implementation. */
144 1.1 christos
145 1.7 christos /* Initialize private data. */
146 1.6 christos static bfd_boolean
147 1.7 christos init_arc_disasm_info (struct disassemble_info *info)
148 1.1 christos {
149 1.7 christos struct arc_disassemble_info *arc_infop
150 1.7 christos = calloc (sizeof (*arc_infop), 1);
151 1.7 christos
152 1.7 christos if (arc_infop == NULL)
153 1.6 christos return FALSE;
154 1.7 christos
155 1.7 christos info->private_data = arc_infop;
156 1.6 christos return TRUE;
157 1.1 christos }
158 1.1 christos
159 1.6 christos /* Add a new element to the decode list. */
160 1.6 christos
161 1.6 christos static void
162 1.6 christos add_to_decodelist (insn_class_t insn_class,
163 1.6 christos insn_subclass_t subclass)
164 1.1 christos {
165 1.6 christos linkclass t = (linkclass) xmalloc (sizeof (skipclass_t));
166 1.6 christos
167 1.6 christos t->insn_class = insn_class;
168 1.6 christos t->subclass = subclass;
169 1.6 christos t->nxt = decodelist;
170 1.6 christos decodelist = t;
171 1.1 christos }
172 1.1 christos
173 1.6 christos /* Return TRUE if we need to skip the opcode from being
174 1.6 christos disassembled. */
175 1.6 christos
176 1.6 christos static bfd_boolean
177 1.7 christos skip_this_opcode (const struct arc_opcode *opcode)
178 1.1 christos {
179 1.6 christos linkclass t = decodelist;
180 1.6 christos
181 1.6 christos /* Check opcode for major 0x06, return if it is not in. */
182 1.7 christos if (arc_opcode_len (opcode) == 4
183 1.9 christos && (OPCODE_32BIT_INSN (opcode->opcode) != 0x06
184 1.9 christos /* Can be an APEX extensions. */
185 1.9 christos && OPCODE_32BIT_INSN (opcode->opcode) != 0x07))
186 1.6 christos return FALSE;
187 1.6 christos
188 1.7 christos /* or not a known truble class. */
189 1.7 christos switch (opcode->insn_class)
190 1.7 christos {
191 1.7 christos case FLOAT:
192 1.7 christos case DSP:
193 1.8 christos case ARITH:
194 1.9 christos case MPY:
195 1.7 christos break;
196 1.7 christos default:
197 1.7 christos return FALSE;
198 1.7 christos }
199 1.7 christos
200 1.7 christos while (t != NULL)
201 1.6 christos {
202 1.6 christos if ((t->insn_class == opcode->insn_class)
203 1.6 christos && (t->subclass == opcode->subclass))
204 1.7 christos return FALSE;
205 1.6 christos t = t->nxt;
206 1.6 christos }
207 1.1 christos
208 1.7 christos return TRUE;
209 1.1 christos }
210 1.1 christos
211 1.6 christos static bfd_vma
212 1.6 christos bfd_getm32 (unsigned int data)
213 1.1 christos {
214 1.6 christos bfd_vma value = 0;
215 1.6 christos
216 1.6 christos value = ((data & 0xff00) | (data & 0xff)) << 16;
217 1.6 christos value |= ((data & 0xff0000) | (data & 0xff000000)) >> 16;
218 1.6 christos return value;
219 1.1 christos }
220 1.1 christos
221 1.6 christos static bfd_boolean
222 1.6 christos special_flag_p (const char *opname,
223 1.6 christos const char *flgname)
224 1.1 christos {
225 1.6 christos const struct arc_flag_special *flg_spec;
226 1.6 christos unsigned i, j, flgidx;
227 1.1 christos
228 1.6 christos for (i = 0; i < arc_num_flag_special; i++)
229 1.1 christos {
230 1.6 christos flg_spec = &arc_flag_special_cases[i];
231 1.6 christos
232 1.6 christos if (strcmp (opname, flg_spec->name))
233 1.6 christos continue;
234 1.6 christos
235 1.6 christos /* Found potential special case instruction. */
236 1.6 christos for (j=0;; ++j)
237 1.6 christos {
238 1.6 christos flgidx = flg_spec->flags[j];
239 1.6 christos if (flgidx == 0)
240 1.6 christos break; /* End of the array. */
241 1.1 christos
242 1.6 christos if (strcmp (flgname, arc_flag_operands[flgidx].name) == 0)
243 1.6 christos return TRUE;
244 1.6 christos }
245 1.1 christos }
246 1.6 christos return FALSE;
247 1.1 christos }
248 1.1 christos
249 1.6 christos /* Find opcode from ARC_TABLE given the instruction described by INSN and
250 1.6 christos INSNLEN. The ISA_MASK restricts the possible matches in ARC_TABLE. */
251 1.6 christos
252 1.6 christos static const struct arc_opcode *
253 1.6 christos find_format_from_table (struct disassemble_info *info,
254 1.6 christos const struct arc_opcode *arc_table,
255 1.7 christos unsigned long long insn,
256 1.6 christos unsigned int insn_len,
257 1.6 christos unsigned isa_mask,
258 1.6 christos bfd_boolean *has_limm,
259 1.6 christos bfd_boolean overlaps)
260 1.1 christos {
261 1.6 christos unsigned int i = 0;
262 1.6 christos const struct arc_opcode *opcode = NULL;
263 1.7 christos const struct arc_opcode *t_op = NULL;
264 1.6 christos const unsigned char *opidx;
265 1.6 christos const unsigned char *flgidx;
266 1.7 christos bfd_boolean warn_p = FALSE;
267 1.6 christos
268 1.6 christos do
269 1.6 christos {
270 1.6 christos bfd_boolean invalid = FALSE;
271 1.6 christos
272 1.6 christos opcode = &arc_table[i++];
273 1.6 christos
274 1.7 christos if (!(opcode->cpu & isa_mask))
275 1.6 christos continue;
276 1.6 christos
277 1.7 christos if (arc_opcode_len (opcode) != (int) insn_len)
278 1.6 christos continue;
279 1.6 christos
280 1.7 christos if ((insn & opcode->mask) != opcode->opcode)
281 1.6 christos continue;
282 1.6 christos
283 1.6 christos *has_limm = FALSE;
284 1.6 christos
285 1.6 christos /* Possible candidate, check the operands. */
286 1.6 christos for (opidx = opcode->operands; *opidx; opidx++)
287 1.6 christos {
288 1.7 christos int value, limmind;
289 1.6 christos const struct arc_operand *operand = &arc_operands[*opidx];
290 1.6 christos
291 1.6 christos if (operand->flags & ARC_OPERAND_FAKE)
292 1.6 christos continue;
293 1.6 christos
294 1.6 christos if (operand->extract)
295 1.7 christos value = (*operand->extract) (insn, &invalid);
296 1.6 christos else
297 1.9 christos value = (insn >> operand->shift) & ((1ull << operand->bits) - 1);
298 1.6 christos
299 1.6 christos /* Check for LIMM indicator. If it is there, then make sure
300 1.6 christos we pick the right format. */
301 1.7 christos limmind = (isa_mask & ARC_OPCODE_ARCV2) ? 0x1E : 0x3E;
302 1.6 christos if (operand->flags & ARC_OPERAND_IR
303 1.6 christos && !(operand->flags & ARC_OPERAND_LIMM))
304 1.1 christos {
305 1.6 christos if ((value == 0x3E && insn_len == 4)
306 1.7 christos || (value == limmind && insn_len == 2))
307 1.1 christos {
308 1.6 christos invalid = TRUE;
309 1.6 christos break;
310 1.1 christos }
311 1.1 christos }
312 1.1 christos
313 1.6 christos if (operand->flags & ARC_OPERAND_LIMM
314 1.6 christos && !(operand->flags & ARC_OPERAND_DUPLICATE))
315 1.6 christos *has_limm = TRUE;
316 1.6 christos }
317 1.6 christos
318 1.6 christos /* Check the flags. */
319 1.6 christos for (flgidx = opcode->flags; *flgidx; flgidx++)
320 1.6 christos {
321 1.6 christos /* Get a valid flag class. */
322 1.6 christos const struct arc_flag_class *cl_flags = &arc_flag_classes[*flgidx];
323 1.6 christos const unsigned *flgopridx;
324 1.6 christos int foundA = 0, foundB = 0;
325 1.6 christos unsigned int value;
326 1.6 christos
327 1.6 christos /* Check first the extensions. */
328 1.6 christos if (cl_flags->flag_class & F_CLASS_EXTEND)
329 1.1 christos {
330 1.7 christos value = (insn & 0x1F);
331 1.6 christos if (arcExtMap_condCodeName (value))
332 1.6 christos continue;
333 1.6 christos }
334 1.1 christos
335 1.7 christos /* Check for the implicit flags. */
336 1.7 christos if (cl_flags->flag_class & F_CLASS_IMPLICIT)
337 1.7 christos continue;
338 1.7 christos
339 1.6 christos for (flgopridx = cl_flags->flags; *flgopridx; ++flgopridx)
340 1.1 christos {
341 1.6 christos const struct arc_flag_operand *flg_operand =
342 1.6 christos &arc_flag_operands[*flgopridx];
343 1.1 christos
344 1.7 christos value = (insn >> flg_operand->shift)
345 1.6 christos & ((1 << flg_operand->bits) - 1);
346 1.6 christos if (value == flg_operand->code)
347 1.6 christos foundA = 1;
348 1.6 christos if (value)
349 1.6 christos foundB = 1;
350 1.1 christos }
351 1.6 christos
352 1.6 christos if (!foundA && foundB)
353 1.1 christos {
354 1.6 christos invalid = TRUE;
355 1.6 christos break;
356 1.6 christos }
357 1.6 christos }
358 1.6 christos
359 1.6 christos if (invalid)
360 1.6 christos continue;
361 1.6 christos
362 1.6 christos if (insn_len == 4
363 1.7 christos && overlaps)
364 1.7 christos {
365 1.7 christos warn_p = TRUE;
366 1.7 christos t_op = opcode;
367 1.7 christos if (skip_this_opcode (opcode))
368 1.7 christos continue;
369 1.7 christos }
370 1.6 christos
371 1.6 christos /* The instruction is valid. */
372 1.6 christos return opcode;
373 1.6 christos }
374 1.6 christos while (opcode->mask);
375 1.6 christos
376 1.7 christos if (warn_p)
377 1.6 christos {
378 1.7 christos info->fprintf_func (info->stream,
379 1.7 christos _("\nWarning: disassembly may be wrong due to "
380 1.7 christos "guessed opcode class choice.\n"
381 1.7 christos "Use -M<class[,class]> to select the correct "
382 1.7 christos "opcode class(es).\n\t\t\t\t"));
383 1.7 christos return t_op;
384 1.6 christos }
385 1.6 christos
386 1.6 christos return NULL;
387 1.6 christos }
388 1.6 christos
389 1.6 christos /* Find opcode for INSN, trying various different sources. The instruction
390 1.6 christos length in INSN_LEN will be updated if the instruction requires a LIMM
391 1.7 christos extension.
392 1.6 christos
393 1.6 christos A pointer to the opcode is placed into OPCODE_RESULT, and ITER is
394 1.7 christos initialised, ready to iterate over the operands of the found opcode. If
395 1.7 christos the found opcode requires a LIMM then the LIMM value will be loaded into a
396 1.7 christos field of ITER.
397 1.6 christos
398 1.6 christos This function returns TRUE in almost all cases, FALSE is reserved to
399 1.7 christos indicate an error (failing to find an opcode is not an error) a returned
400 1.7 christos result of FALSE would indicate that the disassembler can't continue.
401 1.7 christos
402 1.7 christos If no matching opcode is found then the returned result will be TRUE, the
403 1.7 christos value placed into OPCODE_RESULT will be NULL, ITER will be undefined, and
404 1.7 christos INSN_LEN will be unchanged.
405 1.7 christos
406 1.7 christos If a matching opcode is found, then the returned result will be TRUE, the
407 1.7 christos opcode pointer is placed into OPCODE_RESULT, INSN_LEN will be increased by
408 1.7 christos 4 if the instruction requires a LIMM, and the LIMM value will have been
409 1.7 christos loaded into a field of ITER. Finally, ITER will have been initialised so
410 1.7 christos that calls to OPERAND_ITERATOR_NEXT will iterate over the opcode's
411 1.7 christos operands. */
412 1.6 christos
413 1.6 christos static bfd_boolean
414 1.6 christos find_format (bfd_vma memaddr,
415 1.7 christos unsigned long long insn,
416 1.6 christos unsigned int * insn_len,
417 1.6 christos unsigned isa_mask,
418 1.6 christos struct disassemble_info * info,
419 1.6 christos const struct arc_opcode ** opcode_result,
420 1.6 christos struct arc_operand_iterator * iter)
421 1.6 christos {
422 1.6 christos const struct arc_opcode *opcode = NULL;
423 1.9 christos bfd_boolean needs_limm = FALSE;
424 1.7 christos const extInstruction_t *einsn, *i;
425 1.7 christos unsigned limm = 0;
426 1.7 christos struct arc_disassemble_info *arc_infop = info->private_data;
427 1.6 christos
428 1.6 christos /* First, try the extension instructions. */
429 1.7 christos if (*insn_len == 4)
430 1.6 christos {
431 1.7 christos einsn = arcExtMap_insn (OPCODE_32BIT_INSN (insn), insn);
432 1.7 christos for (i = einsn; (i != NULL) && (opcode == NULL); i = i->next)
433 1.7 christos {
434 1.7 christos const char *errmsg = NULL;
435 1.1 christos
436 1.7 christos opcode = arcExtMap_genOpcode (i, isa_mask, &errmsg);
437 1.7 christos if (opcode == NULL)
438 1.7 christos {
439 1.9 christos (*info->fprintf_func) (info->stream,
440 1.9 christos _("An error occurred while generating the "
441 1.9 christos "extension instruction operations"));
442 1.7 christos *opcode_result = NULL;
443 1.7 christos return FALSE;
444 1.7 christos }
445 1.7 christos
446 1.7 christos opcode = find_format_from_table (info, opcode, insn, *insn_len,
447 1.7 christos isa_mask, &needs_limm, FALSE);
448 1.6 christos }
449 1.6 christos }
450 1.1 christos
451 1.6 christos /* Then, try finding the first match in the opcode table. */
452 1.6 christos if (opcode == NULL)
453 1.6 christos opcode = find_format_from_table (info, arc_opcodes, insn, *insn_len,
454 1.6 christos isa_mask, &needs_limm, TRUE);
455 1.1 christos
456 1.9 christos if (opcode != NULL && needs_limm)
457 1.6 christos {
458 1.6 christos bfd_byte buffer[4];
459 1.6 christos int status;
460 1.1 christos
461 1.6 christos status = (*info->read_memory_func) (memaddr + *insn_len, buffer,
462 1.6 christos 4, info);
463 1.6 christos if (status != 0)
464 1.6 christos {
465 1.6 christos opcode = NULL;
466 1.6 christos }
467 1.6 christos else
468 1.6 christos {
469 1.7 christos limm = ARRANGE_ENDIAN (info, buffer);
470 1.6 christos *insn_len += 4;
471 1.6 christos }
472 1.6 christos }
473 1.1 christos
474 1.7 christos if (opcode != NULL)
475 1.6 christos {
476 1.6 christos iter->insn = insn;
477 1.7 christos iter->limm = limm;
478 1.7 christos iter->opcode = opcode;
479 1.7 christos iter->opidx = opcode->operands;
480 1.6 christos }
481 1.1 christos
482 1.6 christos *opcode_result = opcode;
483 1.7 christos
484 1.7 christos /* Update private data. */
485 1.7 christos arc_infop->opcode = opcode;
486 1.9 christos arc_infop->limm = limm;
487 1.7 christos arc_infop->limm_p = needs_limm;
488 1.7 christos
489 1.6 christos return TRUE;
490 1.1 christos }
491 1.1 christos
492 1.1 christos static void
493 1.6 christos print_flags (const struct arc_opcode *opcode,
494 1.7 christos unsigned long long *insn,
495 1.6 christos struct disassemble_info *info)
496 1.1 christos {
497 1.6 christos const unsigned char *flgidx;
498 1.6 christos unsigned int value;
499 1.7 christos struct arc_disassemble_info *arc_infop = info->private_data;
500 1.6 christos
501 1.6 christos /* Now extract and print the flags. */
502 1.6 christos for (flgidx = opcode->flags; *flgidx; flgidx++)
503 1.1 christos {
504 1.6 christos /* Get a valid flag class. */
505 1.6 christos const struct arc_flag_class *cl_flags = &arc_flag_classes[*flgidx];
506 1.6 christos const unsigned *flgopridx;
507 1.1 christos
508 1.6 christos /* Check first the extensions. */
509 1.6 christos if (cl_flags->flag_class & F_CLASS_EXTEND)
510 1.1 christos {
511 1.6 christos const char *name;
512 1.6 christos value = (insn[0] & 0x1F);
513 1.1 christos
514 1.6 christos name = arcExtMap_condCodeName (value);
515 1.6 christos if (name)
516 1.6 christos {
517 1.6 christos (*info->fprintf_func) (info->stream, ".%s", name);
518 1.6 christos continue;
519 1.6 christos }
520 1.1 christos }
521 1.6 christos
522 1.6 christos for (flgopridx = cl_flags->flags; *flgopridx; ++flgopridx)
523 1.1 christos {
524 1.6 christos const struct arc_flag_operand *flg_operand =
525 1.6 christos &arc_flag_operands[*flgopridx];
526 1.6 christos
527 1.7 christos /* Implicit flags are only used for the insn decoder. */
528 1.7 christos if (cl_flags->flag_class & F_CLASS_IMPLICIT)
529 1.7 christos {
530 1.7 christos if (cl_flags->flag_class & F_CLASS_COND)
531 1.7 christos arc_infop->condition_code = flg_operand->code;
532 1.7 christos else if (cl_flags->flag_class & F_CLASS_WB)
533 1.7 christos arc_infop->writeback_mode = flg_operand->code;
534 1.7 christos else if (cl_flags->flag_class & F_CLASS_ZZ)
535 1.7 christos info->data_size = flg_operand->code;
536 1.7 christos continue;
537 1.7 christos }
538 1.7 christos
539 1.6 christos if (!flg_operand->favail)
540 1.6 christos continue;
541 1.6 christos
542 1.6 christos value = (insn[0] >> flg_operand->shift)
543 1.6 christos & ((1 << flg_operand->bits) - 1);
544 1.6 christos if (value == flg_operand->code)
545 1.6 christos {
546 1.6 christos /* FIXME!: print correctly nt/t flag. */
547 1.6 christos if (!special_flag_p (opcode->name, flg_operand->name))
548 1.6 christos (*info->fprintf_func) (info->stream, ".");
549 1.6 christos else if (info->insn_type == dis_dref)
550 1.6 christos {
551 1.6 christos switch (flg_operand->name[0])
552 1.6 christos {
553 1.6 christos case 'b':
554 1.6 christos info->data_size = 1;
555 1.6 christos break;
556 1.6 christos case 'h':
557 1.6 christos case 'w':
558 1.6 christos info->data_size = 2;
559 1.6 christos break;
560 1.6 christos default:
561 1.6 christos info->data_size = 4;
562 1.6 christos break;
563 1.6 christos }
564 1.6 christos }
565 1.6 christos if (flg_operand->name[0] == 'd'
566 1.6 christos && flg_operand->name[1] == 0)
567 1.6 christos info->branch_delay_insns = 1;
568 1.6 christos
569 1.6 christos /* Check if it is a conditional flag. */
570 1.6 christos if (cl_flags->flag_class & F_CLASS_COND)
571 1.6 christos {
572 1.6 christos if (info->insn_type == dis_jsr)
573 1.6 christos info->insn_type = dis_condjsr;
574 1.6 christos else if (info->insn_type == dis_branch)
575 1.6 christos info->insn_type = dis_condbranch;
576 1.7 christos arc_infop->condition_code = flg_operand->code;
577 1.6 christos }
578 1.6 christos
579 1.7 christos /* Check for the write back modes. */
580 1.7 christos if (cl_flags->flag_class & F_CLASS_WB)
581 1.7 christos arc_infop->writeback_mode = flg_operand->code;
582 1.7 christos
583 1.6 christos (*info->fprintf_func) (info->stream, "%s", flg_operand->name);
584 1.6 christos }
585 1.1 christos }
586 1.1 christos }
587 1.1 christos }
588 1.1 christos
589 1.6 christos static const char *
590 1.6 christos get_auxreg (const struct arc_opcode *opcode,
591 1.6 christos int value,
592 1.6 christos unsigned isa_mask)
593 1.6 christos {
594 1.6 christos const char *name;
595 1.6 christos unsigned int i;
596 1.6 christos const struct arc_aux_reg *auxr = &arc_aux_regs[0];
597 1.6 christos
598 1.6 christos if (opcode->insn_class != AUXREG)
599 1.6 christos return NULL;
600 1.6 christos
601 1.6 christos name = arcExtMap_auxRegName (value);
602 1.6 christos if (name)
603 1.6 christos return name;
604 1.6 christos
605 1.6 christos for (i = 0; i < arc_num_aux_regs; i++, auxr++)
606 1.6 christos {
607 1.6 christos if (!(auxr->cpu & isa_mask))
608 1.6 christos continue;
609 1.6 christos
610 1.6 christos if (auxr->subclass != NONE)
611 1.6 christos return NULL;
612 1.1 christos
613 1.6 christos if (auxr->address == value)
614 1.6 christos return auxr->name;
615 1.6 christos }
616 1.6 christos return NULL;
617 1.6 christos }
618 1.6 christos
619 1.6 christos /* Convert a value representing an address type to a string used to refer to
620 1.6 christos the address type in assembly code. */
621 1.6 christos
622 1.6 christos static const char *
623 1.6 christos get_addrtype (int value)
624 1.1 christos {
625 1.6 christos if (value < 0 || value > addrtypenames_max)
626 1.6 christos return addrtypeunknown;
627 1.6 christos
628 1.6 christos return addrtypenames[value];
629 1.6 christos }
630 1.6 christos
631 1.6 christos /* Calculate the instruction length for an instruction starting with MSB
632 1.6 christos and LSB, the most and least significant byte. The ISA_MASK is used to
633 1.6 christos filter the instructions considered to only those that are part of the
634 1.6 christos current architecture.
635 1.6 christos
636 1.6 christos The instruction lengths are calculated from the ARC_OPCODE table, and
637 1.6 christos cached for later use. */
638 1.6 christos
639 1.6 christos static unsigned int
640 1.6 christos arc_insn_length (bfd_byte msb, bfd_byte lsb, struct disassemble_info *info)
641 1.6 christos {
642 1.6 christos bfd_byte major_opcode = msb >> 3;
643 1.1 christos
644 1.6 christos switch (info->mach)
645 1.1 christos {
646 1.6 christos case bfd_mach_arc_arc700:
647 1.6 christos /* The nps400 extension set requires this special casing of the
648 1.6 christos instruction length calculation. Right now this is not causing any
649 1.6 christos problems as none of the known extensions overlap in opcode space,
650 1.6 christos but, if they ever do then we might need to start carrying
651 1.6 christos information around in the elf about which extensions are in use. */
652 1.6 christos if (major_opcode == 0xb)
653 1.6 christos {
654 1.6 christos bfd_byte minor_opcode = lsb & 0x1f;
655 1.6 christos
656 1.7 christos if (minor_opcode < 4)
657 1.7 christos return 6;
658 1.7 christos else if (minor_opcode == 0x10 || minor_opcode == 0x11)
659 1.7 christos return 8;
660 1.6 christos }
661 1.7 christos if (major_opcode == 0xa)
662 1.7 christos {
663 1.7 christos return 8;
664 1.7 christos }
665 1.7 christos /* Fall through. */
666 1.6 christos case bfd_mach_arc_arc600:
667 1.6 christos return (major_opcode > 0xb) ? 2 : 4;
668 1.6 christos break;
669 1.6 christos
670 1.6 christos case bfd_mach_arc_arcv2:
671 1.6 christos return (major_opcode > 0x7) ? 2 : 4;
672 1.6 christos break;
673 1.6 christos
674 1.6 christos default:
675 1.9 christos return 0;
676 1.6 christos }
677 1.6 christos }
678 1.6 christos
679 1.6 christos /* Extract and return the value of OPERAND from the instruction whose value
680 1.6 christos is held in the array INSN. */
681 1.1 christos
682 1.6 christos static int
683 1.7 christos extract_operand_value (const struct arc_operand *operand,
684 1.7 christos unsigned long long insn,
685 1.7 christos unsigned limm)
686 1.6 christos {
687 1.6 christos int value;
688 1.1 christos
689 1.6 christos /* Read the limm operand, if required. */
690 1.6 christos if (operand->flags & ARC_OPERAND_LIMM)
691 1.6 christos /* The second part of the instruction value will have been loaded as
692 1.6 christos part of the find_format call made earlier. */
693 1.7 christos value = limm;
694 1.6 christos else
695 1.6 christos {
696 1.6 christos if (operand->extract)
697 1.7 christos value = (*operand->extract) (insn, (int *) NULL);
698 1.1 christos else
699 1.6 christos {
700 1.6 christos if (operand->flags & ARC_OPERAND_ALIGNED32)
701 1.6 christos {
702 1.7 christos value = (insn >> operand->shift)
703 1.6 christos & ((1 << (operand->bits - 2)) - 1);
704 1.6 christos value = value << 2;
705 1.6 christos }
706 1.6 christos else
707 1.6 christos {
708 1.7 christos value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
709 1.6 christos }
710 1.6 christos if (operand->flags & ARC_OPERAND_SIGNED)
711 1.6 christos {
712 1.6 christos int signbit = 1 << (operand->bits - 1);
713 1.6 christos value = (value ^ signbit) - signbit;
714 1.6 christos }
715 1.6 christos }
716 1.6 christos }
717 1.6 christos
718 1.6 christos return value;
719 1.6 christos }
720 1.6 christos
721 1.6 christos /* Find the next operand, and the operands value from ITER. Return TRUE if
722 1.6 christos there is another operand, otherwise return FALSE. If there is an
723 1.6 christos operand returned then the operand is placed into OPERAND, and the value
724 1.6 christos into VALUE. If there is no operand returned then OPERAND and VALUE are
725 1.6 christos unchanged. */
726 1.6 christos
727 1.6 christos static bfd_boolean
728 1.6 christos operand_iterator_next (struct arc_operand_iterator *iter,
729 1.6 christos const struct arc_operand **operand,
730 1.6 christos int *value)
731 1.6 christos {
732 1.7 christos if (*iter->opidx == 0)
733 1.6 christos {
734 1.7 christos *operand = NULL;
735 1.7 christos return FALSE;
736 1.6 christos }
737 1.1 christos
738 1.7 christos *operand = &arc_operands[*iter->opidx];
739 1.7 christos *value = extract_operand_value (*operand, iter->insn, iter->limm);
740 1.7 christos iter->opidx++;
741 1.6 christos
742 1.6 christos return TRUE;
743 1.6 christos }
744 1.6 christos
745 1.6 christos /* Helper for parsing the options. */
746 1.6 christos
747 1.6 christos static void
748 1.7 christos parse_option (const char *option)
749 1.6 christos {
750 1.8 christos if (disassembler_options_cmp (option, "dsp") == 0)
751 1.6 christos add_to_decodelist (DSP, NONE);
752 1.6 christos
753 1.8 christos else if (disassembler_options_cmp (option, "spfp") == 0)
754 1.6 christos add_to_decodelist (FLOAT, SPX);
755 1.1 christos
756 1.8 christos else if (disassembler_options_cmp (option, "dpfp") == 0)
757 1.6 christos add_to_decodelist (FLOAT, DPX);
758 1.1 christos
759 1.8 christos else if (disassembler_options_cmp (option, "quarkse_em") == 0)
760 1.7 christos {
761 1.7 christos add_to_decodelist (FLOAT, DPX);
762 1.7 christos add_to_decodelist (FLOAT, SPX);
763 1.8 christos add_to_decodelist (FLOAT, QUARKSE1);
764 1.8 christos add_to_decodelist (FLOAT, QUARKSE2);
765 1.7 christos }
766 1.6 christos
767 1.8 christos else if (disassembler_options_cmp (option, "fpuda") == 0)
768 1.6 christos add_to_decodelist (FLOAT, DPA);
769 1.6 christos
770 1.9 christos else if (disassembler_options_cmp (option, "nps400") == 0)
771 1.9 christos {
772 1.9 christos add_to_decodelist (ACL, NPS400);
773 1.9 christos add_to_decodelist (ARITH, NPS400);
774 1.9 christos add_to_decodelist (BITOP, NPS400);
775 1.9 christos add_to_decodelist (BMU, NPS400);
776 1.9 christos add_to_decodelist (CONTROL, NPS400);
777 1.9 christos add_to_decodelist (DMA, NPS400);
778 1.9 christos add_to_decodelist (DPI, NPS400);
779 1.9 christos add_to_decodelist (MEMORY, NPS400);
780 1.9 christos add_to_decodelist (MISC, NPS400);
781 1.9 christos add_to_decodelist (NET, NPS400);
782 1.9 christos add_to_decodelist (PMU, NPS400);
783 1.9 christos add_to_decodelist (PROTOCOL_DECODE, NPS400);
784 1.9 christos add_to_decodelist (ULTRAIP, NPS400);
785 1.9 christos }
786 1.9 christos
787 1.8 christos else if (disassembler_options_cmp (option, "fpus") == 0)
788 1.1 christos {
789 1.6 christos add_to_decodelist (FLOAT, SP);
790 1.6 christos add_to_decodelist (FLOAT, CVT);
791 1.1 christos }
792 1.1 christos
793 1.8 christos else if (disassembler_options_cmp (option, "fpud") == 0)
794 1.6 christos {
795 1.6 christos add_to_decodelist (FLOAT, DP);
796 1.6 christos add_to_decodelist (FLOAT, CVT);
797 1.6 christos }
798 1.8 christos else if (CONST_STRNEQ (option, "hex"))
799 1.8 christos print_hex = TRUE;
800 1.6 christos else
801 1.8 christos /* xgettext:c-format */
802 1.8 christos opcodes_error_handler (_("unrecognised disassembler option: %s"), option);
803 1.8 christos }
804 1.8 christos
805 1.8 christos #define ARC_CPU_TYPE_A6xx(NAME,EXTRA) \
806 1.8 christos { #NAME, ARC_OPCODE_ARC600, "ARC600" }
807 1.8 christos #define ARC_CPU_TYPE_A7xx(NAME,EXTRA) \
808 1.8 christos { #NAME, ARC_OPCODE_ARC700, "ARC700" }
809 1.8 christos #define ARC_CPU_TYPE_AV2EM(NAME,EXTRA) \
810 1.8 christos { #NAME, ARC_OPCODE_ARCv2EM, "ARC EM" }
811 1.8 christos #define ARC_CPU_TYPE_AV2HS(NAME,EXTRA) \
812 1.8 christos { #NAME, ARC_OPCODE_ARCv2HS, "ARC HS" }
813 1.8 christos #define ARC_CPU_TYPE_NONE \
814 1.8 christos { 0, 0, 0 }
815 1.8 christos
816 1.8 christos /* A table of CPU names and opcode sets. */
817 1.8 christos static const struct cpu_type
818 1.8 christos {
819 1.8 christos const char *name;
820 1.8 christos unsigned flags;
821 1.8 christos const char *isa;
822 1.8 christos }
823 1.8 christos cpu_types[] =
824 1.8 christos {
825 1.8 christos #include "elf/arc-cpu.def"
826 1.8 christos };
827 1.8 christos
828 1.8 christos /* Helper for parsing the CPU options. Accept any of the ARC architectures
829 1.8 christos values. OPTION should be a value passed to cpu=. */
830 1.8 christos
831 1.8 christos static unsigned
832 1.8 christos parse_cpu_option (const char *option)
833 1.8 christos {
834 1.8 christos int i;
835 1.8 christos
836 1.8 christos for (i = 0; cpu_types[i].name; ++i)
837 1.8 christos {
838 1.8 christos if (!disassembler_options_cmp (cpu_types[i].name, option))
839 1.8 christos {
840 1.8 christos return cpu_types[i].flags;
841 1.8 christos }
842 1.8 christos }
843 1.8 christos
844 1.8 christos /* xgettext:c-format */
845 1.8 christos opcodes_error_handler (_("unrecognised disassembler CPU option: %s"), option);
846 1.8 christos return ARC_OPCODE_NONE;
847 1.6 christos }
848 1.1 christos
849 1.6 christos /* Go over the options list and parse it. */
850 1.1 christos
851 1.6 christos static void
852 1.7 christos parse_disassembler_options (const char *options)
853 1.6 christos {
854 1.8 christos const char *option;
855 1.8 christos
856 1.6 christos if (options == NULL)
857 1.6 christos return;
858 1.6 christos
859 1.8 christos /* Disassembler might be reused for difference CPU's, and cpu option set for
860 1.8 christos the first one shouldn't be applied to second (which might not have
861 1.8 christos explicit cpu in its options. Therefore it is required to reset enforced
862 1.8 christos CPU when new options are being parsed. */
863 1.8 christos enforced_isa_mask = ARC_OPCODE_NONE;
864 1.8 christos
865 1.8 christos FOR_EACH_DISASSEMBLER_OPTION (option, options)
866 1.8 christos {
867 1.8 christos /* A CPU option? Cannot use STRING_COMMA_LEN because strncmp is also a
868 1.8 christos preprocessor macro. */
869 1.8 christos if (strncmp (option, "cpu=", 4) == 0)
870 1.8 christos /* Strip leading `cpu=`. */
871 1.8 christos enforced_isa_mask = parse_cpu_option (option + 4);
872 1.8 christos else
873 1.8 christos parse_option (option);
874 1.6 christos }
875 1.1 christos }
876 1.1 christos
877 1.7 christos /* Return the instruction type for an instruction described by OPCODE. */
878 1.7 christos
879 1.7 christos static enum dis_insn_type
880 1.7 christos arc_opcode_to_insn_type (const struct arc_opcode *opcode)
881 1.7 christos {
882 1.7 christos enum dis_insn_type insn_type;
883 1.7 christos
884 1.7 christos switch (opcode->insn_class)
885 1.7 christos {
886 1.7 christos case BRANCH:
887 1.7 christos case BBIT0:
888 1.7 christos case BBIT1:
889 1.7 christos case BI:
890 1.7 christos case BIH:
891 1.7 christos case BRCC:
892 1.7 christos case EI:
893 1.7 christos case JLI:
894 1.7 christos case JUMP:
895 1.7 christos case LOOP:
896 1.7 christos if (!strncmp (opcode->name, "bl", 2)
897 1.7 christos || !strncmp (opcode->name, "jl", 2))
898 1.7 christos {
899 1.7 christos if (opcode->subclass == COND)
900 1.7 christos insn_type = dis_condjsr;
901 1.7 christos else
902 1.7 christos insn_type = dis_jsr;
903 1.7 christos }
904 1.7 christos else
905 1.7 christos {
906 1.7 christos if (opcode->subclass == COND)
907 1.7 christos insn_type = dis_condbranch;
908 1.7 christos else
909 1.7 christos insn_type = dis_branch;
910 1.7 christos }
911 1.7 christos break;
912 1.7 christos case LOAD:
913 1.7 christos case STORE:
914 1.7 christos case MEMORY:
915 1.7 christos case ENTER:
916 1.7 christos case PUSH:
917 1.7 christos case POP:
918 1.7 christos insn_type = dis_dref;
919 1.7 christos break;
920 1.7 christos case LEAVE:
921 1.7 christos insn_type = dis_branch;
922 1.7 christos break;
923 1.7 christos default:
924 1.7 christos insn_type = dis_nonbranch;
925 1.7 christos break;
926 1.7 christos }
927 1.7 christos
928 1.7 christos return insn_type;
929 1.7 christos }
930 1.7 christos
931 1.6 christos /* Disassemble ARC instructions. */
932 1.1 christos
933 1.1 christos static int
934 1.6 christos print_insn_arc (bfd_vma memaddr,
935 1.6 christos struct disassemble_info *info)
936 1.1 christos {
937 1.7 christos bfd_byte buffer[8];
938 1.7 christos unsigned int highbyte, lowbyte;
939 1.6 christos int status;
940 1.6 christos unsigned int insn_len;
941 1.7 christos unsigned long long insn = 0;
942 1.8 christos unsigned isa_mask = ARC_OPCODE_NONE;
943 1.6 christos const struct arc_opcode *opcode;
944 1.6 christos bfd_boolean need_comma;
945 1.6 christos bfd_boolean open_braket;
946 1.6 christos int size;
947 1.6 christos const struct arc_operand *operand;
948 1.8 christos int value, vpcl;
949 1.6 christos struct arc_operand_iterator iter;
950 1.7 christos struct arc_disassemble_info *arc_infop;
951 1.8 christos bfd_boolean rpcl = FALSE, rset = FALSE;
952 1.6 christos
953 1.6 christos if (info->disassembler_options)
954 1.6 christos {
955 1.6 christos parse_disassembler_options (info->disassembler_options);
956 1.6 christos
957 1.6 christos /* Avoid repeated parsing of the options. */
958 1.6 christos info->disassembler_options = NULL;
959 1.6 christos }
960 1.6 christos
961 1.7 christos if (info->private_data == NULL && !init_arc_disasm_info (info))
962 1.7 christos return -1;
963 1.7 christos
964 1.6 christos memset (&iter, 0, sizeof (iter));
965 1.7 christos highbyte = ((info->endian == BFD_ENDIAN_LITTLE) ? 1 : 0);
966 1.7 christos lowbyte = ((info->endian == BFD_ENDIAN_LITTLE) ? 0 : 1);
967 1.6 christos
968 1.8 christos /* Figure out CPU type, unless it was enforced via disassembler options. */
969 1.8 christos if (enforced_isa_mask == ARC_OPCODE_NONE)
970 1.8 christos {
971 1.8 christos Elf_Internal_Ehdr *header = NULL;
972 1.8 christos
973 1.8 christos if (info->section && info->section->owner)
974 1.8 christos header = elf_elfheader (info->section->owner);
975 1.6 christos
976 1.8 christos switch (info->mach)
977 1.8 christos {
978 1.8 christos case bfd_mach_arc_arc700:
979 1.8 christos isa_mask = ARC_OPCODE_ARC700;
980 1.8 christos break;
981 1.1 christos
982 1.8 christos case bfd_mach_arc_arc600:
983 1.8 christos isa_mask = ARC_OPCODE_ARC600;
984 1.8 christos break;
985 1.1 christos
986 1.8 christos case bfd_mach_arc_arcv2:
987 1.8 christos default:
988 1.8 christos isa_mask = ARC_OPCODE_ARCv2EM;
989 1.8 christos /* TODO: Perhaps remove definition of header since it is only used at
990 1.8 christos this location. */
991 1.8 christos if (header != NULL
992 1.8 christos && (header->e_flags & EF_ARC_MACH_MSK) == EF_ARC_CPU_ARCV2HS)
993 1.8 christos isa_mask = ARC_OPCODE_ARCv2HS;
994 1.8 christos break;
995 1.1 christos }
996 1.8 christos }
997 1.8 christos else
998 1.8 christos isa_mask = enforced_isa_mask;
999 1.8 christos
1000 1.8 christos if (isa_mask == ARC_OPCODE_ARCv2HS)
1001 1.8 christos {
1002 1.8 christos /* FPU instructions are not extensions for HS. */
1003 1.8 christos add_to_decodelist (FLOAT, SP);
1004 1.8 christos add_to_decodelist (FLOAT, DP);
1005 1.8 christos add_to_decodelist (FLOAT, CVT);
1006 1.6 christos }
1007 1.1 christos
1008 1.6 christos /* This variable may be set by the instruction decoder. It suggests
1009 1.6 christos the number of bytes objdump should display on a single line. If
1010 1.6 christos the instruction decoder sets this, it should always set it to
1011 1.6 christos the same value in order to get reasonable looking output. */
1012 1.6 christos info->bytes_per_line = 8;
1013 1.6 christos
1014 1.6 christos /* In the next lines, we set two info variables control the way
1015 1.6 christos objdump displays the raw data. For example, if bytes_per_line is
1016 1.6 christos 8 and bytes_per_chunk is 4, the output will look like this:
1017 1.6 christos 00: 00000000 00000000
1018 1.6 christos with the chunks displayed according to "display_endian". */
1019 1.6 christos if (info->section
1020 1.6 christos && !(info->section->flags & SEC_CODE))
1021 1.6 christos {
1022 1.6 christos /* This is not a CODE section. */
1023 1.6 christos switch (info->section->size)
1024 1.6 christos {
1025 1.6 christos case 1:
1026 1.6 christos case 2:
1027 1.6 christos case 4:
1028 1.6 christos size = info->section->size;
1029 1.1 christos break;
1030 1.1 christos default:
1031 1.6 christos size = (info->section->size & 0x01) ? 1 : 4;
1032 1.1 christos break;
1033 1.1 christos }
1034 1.6 christos info->bytes_per_chunk = 1;
1035 1.6 christos info->display_endian = info->endian;
1036 1.6 christos }
1037 1.6 christos else
1038 1.6 christos {
1039 1.6 christos size = 2;
1040 1.6 christos info->bytes_per_chunk = 2;
1041 1.6 christos info->display_endian = info->endian;
1042 1.6 christos }
1043 1.1 christos
1044 1.6 christos /* Read the insn into a host word. */
1045 1.6 christos status = (*info->read_memory_func) (memaddr, buffer, size, info);
1046 1.8 christos
1047 1.6 christos if (status != 0)
1048 1.6 christos {
1049 1.6 christos (*info->memory_error_func) (status, memaddr, info);
1050 1.6 christos return -1;
1051 1.6 christos }
1052 1.1 christos
1053 1.6 christos if (info->section
1054 1.6 christos && !(info->section->flags & SEC_CODE))
1055 1.6 christos {
1056 1.6 christos /* Data section. */
1057 1.6 christos unsigned long data;
1058 1.1 christos
1059 1.6 christos data = bfd_get_bits (buffer, size * 8,
1060 1.6 christos info->display_endian == BFD_ENDIAN_BIG);
1061 1.6 christos switch (size)
1062 1.1 christos {
1063 1.6 christos case 1:
1064 1.6 christos (*info->fprintf_func) (info->stream, ".byte\t0x%02lx", data);
1065 1.1 christos break;
1066 1.6 christos case 2:
1067 1.6 christos (*info->fprintf_func) (info->stream, ".short\t0x%04lx", data);
1068 1.1 christos break;
1069 1.6 christos case 4:
1070 1.6 christos (*info->fprintf_func) (info->stream, ".word\t0x%08lx", data);
1071 1.1 christos break;
1072 1.6 christos default:
1073 1.9 christos return -1;
1074 1.1 christos }
1075 1.6 christos return size;
1076 1.6 christos }
1077 1.1 christos
1078 1.7 christos insn_len = arc_insn_length (buffer[highbyte], buffer[lowbyte], info);
1079 1.6 christos pr_debug ("instruction length = %d bytes\n", insn_len);
1080 1.9 christos if (insn_len == 0)
1081 1.9 christos return -1;
1082 1.9 christos
1083 1.7 christos arc_infop = info->private_data;
1084 1.7 christos arc_infop->insn_len = insn_len;
1085 1.1 christos
1086 1.6 christos switch (insn_len)
1087 1.6 christos {
1088 1.6 christos case 2:
1089 1.7 christos insn = (buffer[highbyte] << 8) | buffer[lowbyte];
1090 1.1 christos break;
1091 1.1 christos
1092 1.6 christos case 4:
1093 1.7 christos {
1094 1.7 christos /* This is a long instruction: Read the remaning 2 bytes. */
1095 1.7 christos status = (*info->read_memory_func) (memaddr + 2, &buffer[2], 2, info);
1096 1.7 christos if (status != 0)
1097 1.7 christos {
1098 1.7 christos (*info->memory_error_func) (status, memaddr + 2, info);
1099 1.7 christos return -1;
1100 1.7 christos }
1101 1.7 christos insn = (unsigned long long) ARRANGE_ENDIAN (info, buffer);
1102 1.7 christos }
1103 1.7 christos break;
1104 1.7 christos
1105 1.7 christos case 6:
1106 1.7 christos {
1107 1.7 christos status = (*info->read_memory_func) (memaddr + 2, &buffer[2], 4, info);
1108 1.7 christos if (status != 0)
1109 1.7 christos {
1110 1.7 christos (*info->memory_error_func) (status, memaddr + 2, info);
1111 1.7 christos return -1;
1112 1.7 christos }
1113 1.7 christos insn = (unsigned long long) ARRANGE_ENDIAN (info, &buffer[2]);
1114 1.7 christos insn |= ((unsigned long long) buffer[highbyte] << 40)
1115 1.7 christos | ((unsigned long long) buffer[lowbyte] << 32);
1116 1.7 christos }
1117 1.7 christos break;
1118 1.7 christos
1119 1.7 christos case 8:
1120 1.7 christos {
1121 1.7 christos status = (*info->read_memory_func) (memaddr + 2, &buffer[2], 6, info);
1122 1.7 christos if (status != 0)
1123 1.7 christos {
1124 1.7 christos (*info->memory_error_func) (status, memaddr + 2, info);
1125 1.7 christos return -1;
1126 1.7 christos }
1127 1.7 christos insn =
1128 1.7 christos ((((unsigned long long) ARRANGE_ENDIAN (info, buffer)) << 32)
1129 1.7 christos | ((unsigned long long) ARRANGE_ENDIAN (info, &buffer[4])));
1130 1.7 christos }
1131 1.1 christos break;
1132 1.7 christos
1133 1.7 christos default:
1134 1.7 christos /* There is no instruction whose length is not 2, 4, 6, or 8. */
1135 1.9 christos return -1;
1136 1.1 christos }
1137 1.1 christos
1138 1.7 christos pr_debug ("instruction value = %llx\n", insn);
1139 1.7 christos
1140 1.6 christos /* Set some defaults for the insn info. */
1141 1.6 christos info->insn_info_valid = 1;
1142 1.6 christos info->branch_delay_insns = 0;
1143 1.7 christos info->data_size = 4;
1144 1.6 christos info->insn_type = dis_nonbranch;
1145 1.6 christos info->target = 0;
1146 1.6 christos info->target2 = 0;
1147 1.6 christos
1148 1.6 christos /* FIXME to be moved in dissasemble_init_for_target. */
1149 1.6 christos info->disassembler_needs_relocs = TRUE;
1150 1.6 christos
1151 1.6 christos /* Find the first match in the opcode table. */
1152 1.6 christos if (!find_format (memaddr, insn, &insn_len, isa_mask, info, &opcode, &iter))
1153 1.6 christos return -1;
1154 1.6 christos
1155 1.6 christos if (!opcode)
1156 1.6 christos {
1157 1.7 christos switch (insn_len)
1158 1.7 christos {
1159 1.7 christos case 2:
1160 1.8 christos (*info->fprintf_func) (info->stream, ".shor\t%#04llx",
1161 1.7 christos insn & 0xffff);
1162 1.7 christos break;
1163 1.9 christos
1164 1.7 christos case 4:
1165 1.8 christos (*info->fprintf_func) (info->stream, ".word\t%#08llx",
1166 1.7 christos insn & 0xffffffff);
1167 1.7 christos break;
1168 1.9 christos
1169 1.7 christos case 6:
1170 1.8 christos (*info->fprintf_func) (info->stream, ".long\t%#08llx",
1171 1.7 christos insn & 0xffffffff);
1172 1.8 christos (*info->fprintf_func) (info->stream, ".long\t%#04llx",
1173 1.7 christos (insn >> 32) & 0xffff);
1174 1.7 christos break;
1175 1.9 christos
1176 1.7 christos case 8:
1177 1.8 christos (*info->fprintf_func) (info->stream, ".long\t%#08llx",
1178 1.7 christos insn & 0xffffffff);
1179 1.8 christos (*info->fprintf_func) (info->stream, ".long\t%#08llx",
1180 1.7 christos insn >> 32);
1181 1.7 christos break;
1182 1.9 christos
1183 1.7 christos default:
1184 1.9 christos return -1;
1185 1.7 christos }
1186 1.6 christos
1187 1.6 christos info->insn_type = dis_noninsn;
1188 1.6 christos return insn_len;
1189 1.6 christos }
1190 1.6 christos
1191 1.6 christos /* Print the mnemonic. */
1192 1.6 christos (*info->fprintf_func) (info->stream, "%s", opcode->name);
1193 1.6 christos
1194 1.6 christos /* Preselect the insn class. */
1195 1.7 christos info->insn_type = arc_opcode_to_insn_type (opcode);
1196 1.6 christos
1197 1.7 christos pr_debug ("%s: 0x%08llx\n", opcode->name, opcode->opcode);
1198 1.1 christos
1199 1.7 christos print_flags (opcode, &insn, info);
1200 1.6 christos
1201 1.6 christos if (opcode->operands[0] != 0)
1202 1.6 christos (*info->fprintf_func) (info->stream, "\t");
1203 1.1 christos
1204 1.6 christos need_comma = FALSE;
1205 1.6 christos open_braket = FALSE;
1206 1.7 christos arc_infop->operands_count = 0;
1207 1.1 christos
1208 1.6 christos /* Now extract and print the operands. */
1209 1.6 christos operand = NULL;
1210 1.8 christos vpcl = 0;
1211 1.6 christos while (operand_iterator_next (&iter, &operand, &value))
1212 1.6 christos {
1213 1.6 christos if (open_braket && (operand->flags & ARC_OPERAND_BRAKET))
1214 1.1 christos {
1215 1.6 christos (*info->fprintf_func) (info->stream, "]");
1216 1.6 christos open_braket = FALSE;
1217 1.6 christos continue;
1218 1.1 christos }
1219 1.1 christos
1220 1.6 christos /* Only take input from real operands. */
1221 1.6 christos if (ARC_OPERAND_IS_FAKE (operand))
1222 1.6 christos continue;
1223 1.1 christos
1224 1.6 christos if ((operand->flags & ARC_OPERAND_IGNORE)
1225 1.6 christos && (operand->flags & ARC_OPERAND_IR)
1226 1.7 christos && value == -1)
1227 1.6 christos continue;
1228 1.1 christos
1229 1.6 christos if (operand->flags & ARC_OPERAND_COLON)
1230 1.7 christos {
1231 1.7 christos (*info->fprintf_func) (info->stream, ":");
1232 1.7 christos continue;
1233 1.7 christos }
1234 1.1 christos
1235 1.6 christos if (need_comma)
1236 1.6 christos (*info->fprintf_func) (info->stream, ",");
1237 1.1 christos
1238 1.6 christos if (!open_braket && (operand->flags & ARC_OPERAND_BRAKET))
1239 1.1 christos {
1240 1.6 christos (*info->fprintf_func) (info->stream, "[");
1241 1.6 christos open_braket = TRUE;
1242 1.6 christos need_comma = FALSE;
1243 1.6 christos continue;
1244 1.1 christos }
1245 1.6 christos
1246 1.6 christos need_comma = TRUE;
1247 1.6 christos
1248 1.8 christos if (operand->flags & ARC_OPERAND_PCREL)
1249 1.8 christos {
1250 1.8 christos rpcl = TRUE;
1251 1.8 christos vpcl = value;
1252 1.8 christos rset = TRUE;
1253 1.8 christos
1254 1.8 christos info->target = (bfd_vma) (memaddr & ~3) + value;
1255 1.8 christos }
1256 1.8 christos else if (!(operand->flags & ARC_OPERAND_IR))
1257 1.8 christos {
1258 1.8 christos vpcl = value;
1259 1.8 christos rset = TRUE;
1260 1.8 christos }
1261 1.8 christos
1262 1.6 christos /* Print the operand as directed by the flags. */
1263 1.6 christos if (operand->flags & ARC_OPERAND_IR)
1264 1.1 christos {
1265 1.6 christos const char *rname;
1266 1.6 christos
1267 1.6 christos assert (value >=0 && value < 64);
1268 1.6 christos rname = arcExtMap_coreRegName (value);
1269 1.6 christos if (!rname)
1270 1.6 christos rname = regnames[value];
1271 1.6 christos (*info->fprintf_func) (info->stream, "%s", rname);
1272 1.9 christos
1273 1.9 christos /* Check if we have a double register to print. */
1274 1.6 christos if (operand->flags & ARC_OPERAND_TRUNCATE)
1275 1.1 christos {
1276 1.9 christos if ((value & 0x01) == 0)
1277 1.9 christos {
1278 1.9 christos rname = arcExtMap_coreRegName (value + 1);
1279 1.9 christos if (!rname)
1280 1.9 christos rname = regnames[value + 1];
1281 1.9 christos }
1282 1.9 christos else
1283 1.9 christos rname = _("\nWarning: illegal use of double register "
1284 1.9 christos "pair.\n");
1285 1.6 christos (*info->fprintf_func) (info->stream, "%s", rname);
1286 1.1 christos }
1287 1.8 christos if (value == 63)
1288 1.8 christos rpcl = TRUE;
1289 1.8 christos else
1290 1.8 christos rpcl = FALSE;
1291 1.6 christos }
1292 1.6 christos else if (operand->flags & ARC_OPERAND_LIMM)
1293 1.6 christos {
1294 1.6 christos const char *rname = get_auxreg (opcode, value, isa_mask);
1295 1.6 christos
1296 1.6 christos if (rname && open_braket)
1297 1.6 christos (*info->fprintf_func) (info->stream, "%s", rname);
1298 1.1 christos else
1299 1.6 christos {
1300 1.6 christos (*info->fprintf_func) (info->stream, "%#x", value);
1301 1.6 christos if (info->insn_type == dis_branch
1302 1.6 christos || info->insn_type == dis_jsr)
1303 1.6 christos info->target = (bfd_vma) value;
1304 1.6 christos }
1305 1.1 christos }
1306 1.6 christos else if (operand->flags & ARC_OPERAND_SIGNED)
1307 1.1 christos {
1308 1.6 christos const char *rname = get_auxreg (opcode, value, isa_mask);
1309 1.6 christos if (rname && open_braket)
1310 1.6 christos (*info->fprintf_func) (info->stream, "%s", rname);
1311 1.6 christos else
1312 1.8 christos {
1313 1.8 christos if (print_hex)
1314 1.8 christos (*info->fprintf_func) (info->stream, "%#x", value);
1315 1.8 christos else
1316 1.8 christos (*info->fprintf_func) (info->stream, "%d", value);
1317 1.8 christos }
1318 1.1 christos }
1319 1.6 christos else if (operand->flags & ARC_OPERAND_ADDRTYPE)
1320 1.7 christos {
1321 1.7 christos const char *addrtype = get_addrtype (value);
1322 1.7 christos (*info->fprintf_func) (info->stream, "%s", addrtype);
1323 1.7 christos /* A colon follow an address type. */
1324 1.7 christos need_comma = FALSE;
1325 1.7 christos }
1326 1.1 christos else
1327 1.1 christos {
1328 1.6 christos if (operand->flags & ARC_OPERAND_TRUNCATE
1329 1.6 christos && !(operand->flags & ARC_OPERAND_ALIGNED32)
1330 1.6 christos && !(operand->flags & ARC_OPERAND_ALIGNED16)
1331 1.8 christos && value >= 0 && value <= 14)
1332 1.8 christos {
1333 1.8 christos /* Leave/Enter mnemonics. */
1334 1.8 christos switch (value)
1335 1.8 christos {
1336 1.8 christos case 0:
1337 1.8 christos need_comma = FALSE;
1338 1.8 christos break;
1339 1.8 christos case 1:
1340 1.8 christos (*info->fprintf_func) (info->stream, "r13");
1341 1.8 christos break;
1342 1.8 christos default:
1343 1.8 christos (*info->fprintf_func) (info->stream, "r13-%s",
1344 1.8 christos regnames[13 + value - 1]);
1345 1.8 christos break;
1346 1.8 christos }
1347 1.8 christos rpcl = FALSE;
1348 1.8 christos rset = FALSE;
1349 1.8 christos }
1350 1.6 christos else
1351 1.1 christos {
1352 1.6 christos const char *rname = get_auxreg (opcode, value, isa_mask);
1353 1.6 christos if (rname && open_braket)
1354 1.6 christos (*info->fprintf_func) (info->stream, "%s", rname);
1355 1.6 christos else
1356 1.6 christos (*info->fprintf_func) (info->stream, "%#x", value);
1357 1.1 christos }
1358 1.1 christos }
1359 1.7 christos
1360 1.7 christos if (operand->flags & ARC_OPERAND_LIMM)
1361 1.7 christos {
1362 1.7 christos arc_infop->operands[arc_infop->operands_count].kind
1363 1.7 christos = ARC_OPERAND_KIND_LIMM;
1364 1.7 christos /* It is not important to have exactly the LIMM indicator
1365 1.7 christos here. */
1366 1.7 christos arc_infop->operands[arc_infop->operands_count].value = 63;
1367 1.7 christos }
1368 1.7 christos else
1369 1.7 christos {
1370 1.7 christos arc_infop->operands[arc_infop->operands_count].value = value;
1371 1.7 christos arc_infop->operands[arc_infop->operands_count].kind
1372 1.7 christos = (operand->flags & ARC_OPERAND_IR
1373 1.7 christos ? ARC_OPERAND_KIND_REG
1374 1.7 christos : ARC_OPERAND_KIND_SHIMM);
1375 1.7 christos }
1376 1.7 christos arc_infop->operands_count ++;
1377 1.1 christos }
1378 1.1 christos
1379 1.8 christos /* Pretty print extra info for pc-relative operands. */
1380 1.8 christos if (rpcl && rset)
1381 1.8 christos {
1382 1.8 christos if (info->flags & INSN_HAS_RELOC)
1383 1.8 christos /* If the instruction has a reloc associated with it, then the
1384 1.8 christos offset field in the instruction will actually be the addend
1385 1.8 christos for the reloc. (We are using REL type relocs). In such
1386 1.8 christos cases, we can ignore the pc when computing addresses, since
1387 1.8 christos the addend is not currently pc-relative. */
1388 1.8 christos memaddr = 0;
1389 1.8 christos
1390 1.8 christos (*info->fprintf_func) (info->stream, "\t;");
1391 1.8 christos (*info->print_address_func) ((memaddr & ~3) + vpcl, info);
1392 1.8 christos }
1393 1.8 christos
1394 1.6 christos return insn_len;
1395 1.1 christos }
1396 1.1 christos
1397 1.1 christos
1398 1.6 christos disassembler_ftype
1399 1.6 christos arc_get_disassembler (bfd *abfd)
1400 1.6 christos {
1401 1.7 christos /* BFD my be absent, if opcodes is invoked from the debugger that
1402 1.7 christos has connected to remote target and doesn't have an ELF file. */
1403 1.7 christos if (abfd != NULL)
1404 1.7 christos {
1405 1.7 christos /* Read the extension insns and registers, if any. */
1406 1.7 christos build_ARC_extmap (abfd);
1407 1.6 christos #ifdef DEBUG
1408 1.7 christos dump_ARC_extmap ();
1409 1.6 christos #endif
1410 1.7 christos }
1411 1.1 christos
1412 1.6 christos return print_insn_arc;
1413 1.1 christos }
1414 1.1 christos
1415 1.6 christos void
1416 1.6 christos print_arc_disassembler_options (FILE *stream)
1417 1.1 christos {
1418 1.8 christos int i;
1419 1.8 christos
1420 1.6 christos fprintf (stream, _("\n\
1421 1.6 christos The following ARC specific disassembler options are supported for use \n\
1422 1.6 christos with -M switch (multiple options should be separated by commas):\n"));
1423 1.6 christos
1424 1.8 christos /* cpu=... options. */
1425 1.8 christos for (i = 0; cpu_types[i].name; ++i)
1426 1.8 christos {
1427 1.8 christos /* As of now all value CPU values are less than 16 characters. */
1428 1.8 christos fprintf (stream, " cpu=%-16s\tEnforce %s ISA.\n",
1429 1.8 christos cpu_types[i].name, cpu_types[i].isa);
1430 1.8 christos }
1431 1.8 christos
1432 1.6 christos fprintf (stream, _("\
1433 1.6 christos dsp Recognize DSP instructions.\n"));
1434 1.6 christos fprintf (stream, _("\
1435 1.6 christos spfp Recognize FPX SP instructions.\n"));
1436 1.6 christos fprintf (stream, _("\
1437 1.6 christos dpfp Recognize FPX DP instructions.\n"));
1438 1.6 christos fprintf (stream, _("\
1439 1.6 christos quarkse_em Recognize FPU QuarkSE-EM instructions.\n"));
1440 1.6 christos fprintf (stream, _("\
1441 1.6 christos fpuda Recognize double assist FPU instructions.\n"));
1442 1.6 christos fprintf (stream, _("\
1443 1.6 christos fpus Recognize single precision FPU instructions.\n"));
1444 1.6 christos fprintf (stream, _("\
1445 1.6 christos fpud Recognize double precision FPU instructions.\n"));
1446 1.8 christos fprintf (stream, _("\
1447 1.9 christos nps400 Recognize NPS400 instructions.\n"));
1448 1.9 christos fprintf (stream, _("\
1449 1.8 christos hex Use only hexadecimal number to print immediates.\n"));
1450 1.1 christos }
1451 1.1 christos
1452 1.7 christos void arc_insn_decode (bfd_vma addr,
1453 1.7 christos struct disassemble_info *info,
1454 1.7 christos disassembler_ftype disasm_func,
1455 1.7 christos struct arc_instruction *insn)
1456 1.7 christos {
1457 1.7 christos const struct arc_opcode *opcode;
1458 1.7 christos struct arc_disassemble_info *arc_infop;
1459 1.7 christos
1460 1.7 christos /* Ensure that insn would be in the reset state. */
1461 1.7 christos memset (insn, 0, sizeof (struct arc_instruction));
1462 1.7 christos
1463 1.7 christos /* There was an error when disassembling, for example memory read error. */
1464 1.7 christos if (disasm_func (addr, info) < 0)
1465 1.7 christos {
1466 1.7 christos insn->valid = FALSE;
1467 1.7 christos return;
1468 1.7 christos }
1469 1.7 christos
1470 1.7 christos assert (info->private_data != NULL);
1471 1.7 christos arc_infop = info->private_data;
1472 1.7 christos
1473 1.7 christos insn->length = arc_infop->insn_len;;
1474 1.7 christos insn->address = addr;
1475 1.7 christos
1476 1.7 christos /* Quick exit if memory at this address is not an instruction. */
1477 1.7 christos if (info->insn_type == dis_noninsn)
1478 1.7 christos {
1479 1.7 christos insn->valid = FALSE;
1480 1.7 christos return;
1481 1.7 christos }
1482 1.7 christos
1483 1.7 christos insn->valid = TRUE;
1484 1.7 christos
1485 1.7 christos opcode = (const struct arc_opcode *) arc_infop->opcode;
1486 1.7 christos insn->insn_class = opcode->insn_class;
1487 1.7 christos insn->limm_value = arc_infop->limm;
1488 1.7 christos insn->limm_p = arc_infop->limm_p;
1489 1.7 christos
1490 1.7 christos insn->is_control_flow = (info->insn_type == dis_branch
1491 1.7 christos || info->insn_type == dis_condbranch
1492 1.7 christos || info->insn_type == dis_jsr
1493 1.7 christos || info->insn_type == dis_condjsr);
1494 1.7 christos
1495 1.7 christos insn->has_delay_slot = info->branch_delay_insns;
1496 1.7 christos insn->writeback_mode
1497 1.7 christos = (enum arc_ldst_writeback_mode) arc_infop->writeback_mode;
1498 1.7 christos insn->data_size_mode = info->data_size;
1499 1.7 christos insn->condition_code = arc_infop->condition_code;
1500 1.7 christos memcpy (insn->operands, arc_infop->operands,
1501 1.7 christos sizeof (struct arc_insn_operand) * MAX_INSN_ARGS);
1502 1.7 christos insn->operands_count = arc_infop->operands_count;
1503 1.7 christos }
1504 1.1 christos
1505 1.6 christos /* Local variables:
1506 1.6 christos eval: (c-set-style "gnu")
1507 1.6 christos indent-tabs-mode: t
1508 1.6 christos End: */
1509