arc-dis.c revision 1.9.2.1 1 1.1 christos /* Instruction printing code for the ARC.
2 1.9.2.1 perseant Copyright (C) 1994-2022 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.9.2.1 perseant bool 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.9.2.1 perseant static bool 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.9.2.1 perseant static bool
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.9.2.1 perseant return false;
154 1.7 christos
155 1.7 christos info->private_data = arc_infop;
156 1.9.2.1 perseant 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.9.2.1 perseant static bool
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.9.2.1 perseant 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.9.2.1 perseant 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.9.2.1 perseant return false;
205 1.6 christos t = t->nxt;
206 1.6 christos }
207 1.1 christos
208 1.9.2.1 perseant 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.9.2.1 perseant static bool
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.9.2.1 perseant return true;
244 1.6 christos }
245 1.1 christos }
246 1.9.2.1 perseant 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.9.2.1 perseant bool *has_limm,
259 1.9.2.1 perseant bool 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.9.2.1 perseant bool warn_p = false;
267 1.6 christos
268 1.6 christos do
269 1.6 christos {
270 1.9.2.1 perseant bool 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.9.2.1 perseant *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.9.2.1 perseant 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.9.2.1 perseant *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.9.2.1 perseant 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.9.2.1 perseant 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.9.2.1 perseant info->fprintf_styled_func
379 1.9.2.1 perseant (info->stream, dis_style_text,
380 1.9.2.1 perseant _("\nWarning: disassembly may be wrong due to "
381 1.9.2.1 perseant "guessed opcode class choice.\n"
382 1.9.2.1 perseant "Use -M<class[,class]> to select the correct "
383 1.9.2.1 perseant "opcode class(es).\n\t\t\t\t"));
384 1.7 christos return t_op;
385 1.6 christos }
386 1.6 christos
387 1.6 christos return NULL;
388 1.6 christos }
389 1.6 christos
390 1.6 christos /* Find opcode for INSN, trying various different sources. The instruction
391 1.6 christos length in INSN_LEN will be updated if the instruction requires a LIMM
392 1.7 christos extension.
393 1.6 christos
394 1.6 christos A pointer to the opcode is placed into OPCODE_RESULT, and ITER is
395 1.7 christos initialised, ready to iterate over the operands of the found opcode. If
396 1.7 christos the found opcode requires a LIMM then the LIMM value will be loaded into a
397 1.7 christos field of ITER.
398 1.6 christos
399 1.6 christos This function returns TRUE in almost all cases, FALSE is reserved to
400 1.7 christos indicate an error (failing to find an opcode is not an error) a returned
401 1.7 christos result of FALSE would indicate that the disassembler can't continue.
402 1.7 christos
403 1.7 christos If no matching opcode is found then the returned result will be TRUE, the
404 1.7 christos value placed into OPCODE_RESULT will be NULL, ITER will be undefined, and
405 1.7 christos INSN_LEN will be unchanged.
406 1.7 christos
407 1.7 christos If a matching opcode is found, then the returned result will be TRUE, the
408 1.7 christos opcode pointer is placed into OPCODE_RESULT, INSN_LEN will be increased by
409 1.7 christos 4 if the instruction requires a LIMM, and the LIMM value will have been
410 1.7 christos loaded into a field of ITER. Finally, ITER will have been initialised so
411 1.7 christos that calls to OPERAND_ITERATOR_NEXT will iterate over the opcode's
412 1.7 christos operands. */
413 1.6 christos
414 1.9.2.1 perseant static bool
415 1.6 christos find_format (bfd_vma memaddr,
416 1.7 christos unsigned long long insn,
417 1.6 christos unsigned int * insn_len,
418 1.6 christos unsigned isa_mask,
419 1.6 christos struct disassemble_info * info,
420 1.6 christos const struct arc_opcode ** opcode_result,
421 1.6 christos struct arc_operand_iterator * iter)
422 1.6 christos {
423 1.6 christos const struct arc_opcode *opcode = NULL;
424 1.9.2.1 perseant bool needs_limm = false;
425 1.7 christos const extInstruction_t *einsn, *i;
426 1.7 christos unsigned limm = 0;
427 1.7 christos struct arc_disassemble_info *arc_infop = info->private_data;
428 1.6 christos
429 1.6 christos /* First, try the extension instructions. */
430 1.7 christos if (*insn_len == 4)
431 1.6 christos {
432 1.7 christos einsn = arcExtMap_insn (OPCODE_32BIT_INSN (insn), insn);
433 1.7 christos for (i = einsn; (i != NULL) && (opcode == NULL); i = i->next)
434 1.7 christos {
435 1.7 christos const char *errmsg = NULL;
436 1.1 christos
437 1.7 christos opcode = arcExtMap_genOpcode (i, isa_mask, &errmsg);
438 1.7 christos if (opcode == NULL)
439 1.7 christos {
440 1.9.2.1 perseant (*info->fprintf_styled_func)
441 1.9.2.1 perseant (info->stream, dis_style_text,
442 1.9.2.1 perseant _("An error occurred while generating "
443 1.9.2.1 perseant "the extension instruction operations"));
444 1.7 christos *opcode_result = NULL;
445 1.9.2.1 perseant return false;
446 1.7 christos }
447 1.7 christos
448 1.7 christos opcode = find_format_from_table (info, opcode, insn, *insn_len,
449 1.9.2.1 perseant isa_mask, &needs_limm, false);
450 1.6 christos }
451 1.6 christos }
452 1.1 christos
453 1.6 christos /* Then, try finding the first match in the opcode table. */
454 1.6 christos if (opcode == NULL)
455 1.6 christos opcode = find_format_from_table (info, arc_opcodes, insn, *insn_len,
456 1.9.2.1 perseant isa_mask, &needs_limm, true);
457 1.1 christos
458 1.9 christos if (opcode != NULL && needs_limm)
459 1.6 christos {
460 1.6 christos bfd_byte buffer[4];
461 1.6 christos int status;
462 1.1 christos
463 1.6 christos status = (*info->read_memory_func) (memaddr + *insn_len, buffer,
464 1.6 christos 4, info);
465 1.6 christos if (status != 0)
466 1.6 christos {
467 1.6 christos opcode = NULL;
468 1.6 christos }
469 1.6 christos else
470 1.6 christos {
471 1.7 christos limm = ARRANGE_ENDIAN (info, buffer);
472 1.6 christos *insn_len += 4;
473 1.6 christos }
474 1.6 christos }
475 1.1 christos
476 1.7 christos if (opcode != NULL)
477 1.6 christos {
478 1.6 christos iter->insn = insn;
479 1.7 christos iter->limm = limm;
480 1.7 christos iter->opcode = opcode;
481 1.7 christos iter->opidx = opcode->operands;
482 1.6 christos }
483 1.1 christos
484 1.6 christos *opcode_result = opcode;
485 1.7 christos
486 1.7 christos /* Update private data. */
487 1.7 christos arc_infop->opcode = opcode;
488 1.9 christos arc_infop->limm = limm;
489 1.7 christos arc_infop->limm_p = needs_limm;
490 1.7 christos
491 1.9.2.1 perseant return true;
492 1.1 christos }
493 1.1 christos
494 1.1 christos static void
495 1.6 christos print_flags (const struct arc_opcode *opcode,
496 1.7 christos unsigned long long *insn,
497 1.6 christos struct disassemble_info *info)
498 1.1 christos {
499 1.6 christos const unsigned char *flgidx;
500 1.6 christos unsigned int value;
501 1.7 christos struct arc_disassemble_info *arc_infop = info->private_data;
502 1.6 christos
503 1.6 christos /* Now extract and print the flags. */
504 1.6 christos for (flgidx = opcode->flags; *flgidx; flgidx++)
505 1.1 christos {
506 1.6 christos /* Get a valid flag class. */
507 1.6 christos const struct arc_flag_class *cl_flags = &arc_flag_classes[*flgidx];
508 1.6 christos const unsigned *flgopridx;
509 1.1 christos
510 1.6 christos /* Check first the extensions. */
511 1.6 christos if (cl_flags->flag_class & F_CLASS_EXTEND)
512 1.1 christos {
513 1.6 christos const char *name;
514 1.6 christos value = (insn[0] & 0x1F);
515 1.1 christos
516 1.6 christos name = arcExtMap_condCodeName (value);
517 1.6 christos if (name)
518 1.6 christos {
519 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_mnemonic,
520 1.9.2.1 perseant ".%s", name);
521 1.6 christos continue;
522 1.6 christos }
523 1.1 christos }
524 1.6 christos
525 1.6 christos for (flgopridx = cl_flags->flags; *flgopridx; ++flgopridx)
526 1.1 christos {
527 1.6 christos const struct arc_flag_operand *flg_operand =
528 1.6 christos &arc_flag_operands[*flgopridx];
529 1.6 christos
530 1.7 christos /* Implicit flags are only used for the insn decoder. */
531 1.7 christos if (cl_flags->flag_class & F_CLASS_IMPLICIT)
532 1.7 christos {
533 1.7 christos if (cl_flags->flag_class & F_CLASS_COND)
534 1.7 christos arc_infop->condition_code = flg_operand->code;
535 1.7 christos else if (cl_flags->flag_class & F_CLASS_WB)
536 1.7 christos arc_infop->writeback_mode = flg_operand->code;
537 1.7 christos else if (cl_flags->flag_class & F_CLASS_ZZ)
538 1.7 christos info->data_size = flg_operand->code;
539 1.7 christos continue;
540 1.7 christos }
541 1.7 christos
542 1.6 christos if (!flg_operand->favail)
543 1.6 christos continue;
544 1.6 christos
545 1.6 christos value = (insn[0] >> flg_operand->shift)
546 1.6 christos & ((1 << flg_operand->bits) - 1);
547 1.6 christos if (value == flg_operand->code)
548 1.6 christos {
549 1.6 christos /* FIXME!: print correctly nt/t flag. */
550 1.6 christos if (!special_flag_p (opcode->name, flg_operand->name))
551 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream,
552 1.9.2.1 perseant dis_style_mnemonic, ".");
553 1.6 christos else if (info->insn_type == dis_dref)
554 1.6 christos {
555 1.6 christos switch (flg_operand->name[0])
556 1.6 christos {
557 1.6 christos case 'b':
558 1.6 christos info->data_size = 1;
559 1.6 christos break;
560 1.6 christos case 'h':
561 1.6 christos case 'w':
562 1.6 christos info->data_size = 2;
563 1.6 christos break;
564 1.6 christos default:
565 1.6 christos info->data_size = 4;
566 1.6 christos break;
567 1.6 christos }
568 1.6 christos }
569 1.6 christos if (flg_operand->name[0] == 'd'
570 1.6 christos && flg_operand->name[1] == 0)
571 1.6 christos info->branch_delay_insns = 1;
572 1.6 christos
573 1.6 christos /* Check if it is a conditional flag. */
574 1.6 christos if (cl_flags->flag_class & F_CLASS_COND)
575 1.6 christos {
576 1.6 christos if (info->insn_type == dis_jsr)
577 1.6 christos info->insn_type = dis_condjsr;
578 1.6 christos else if (info->insn_type == dis_branch)
579 1.6 christos info->insn_type = dis_condbranch;
580 1.7 christos arc_infop->condition_code = flg_operand->code;
581 1.6 christos }
582 1.6 christos
583 1.7 christos /* Check for the write back modes. */
584 1.7 christos if (cl_flags->flag_class & F_CLASS_WB)
585 1.7 christos arc_infop->writeback_mode = flg_operand->code;
586 1.7 christos
587 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_mnemonic,
588 1.9.2.1 perseant "%s", flg_operand->name);
589 1.6 christos }
590 1.1 christos }
591 1.1 christos }
592 1.1 christos }
593 1.1 christos
594 1.6 christos static const char *
595 1.6 christos get_auxreg (const struct arc_opcode *opcode,
596 1.6 christos int value,
597 1.6 christos unsigned isa_mask)
598 1.6 christos {
599 1.6 christos const char *name;
600 1.6 christos unsigned int i;
601 1.6 christos const struct arc_aux_reg *auxr = &arc_aux_regs[0];
602 1.6 christos
603 1.6 christos if (opcode->insn_class != AUXREG)
604 1.6 christos return NULL;
605 1.6 christos
606 1.6 christos name = arcExtMap_auxRegName (value);
607 1.6 christos if (name)
608 1.6 christos return name;
609 1.6 christos
610 1.6 christos for (i = 0; i < arc_num_aux_regs; i++, auxr++)
611 1.6 christos {
612 1.6 christos if (!(auxr->cpu & isa_mask))
613 1.6 christos continue;
614 1.6 christos
615 1.6 christos if (auxr->subclass != NONE)
616 1.6 christos return NULL;
617 1.1 christos
618 1.6 christos if (auxr->address == value)
619 1.6 christos return auxr->name;
620 1.6 christos }
621 1.6 christos return NULL;
622 1.6 christos }
623 1.6 christos
624 1.6 christos /* Convert a value representing an address type to a string used to refer to
625 1.6 christos the address type in assembly code. */
626 1.6 christos
627 1.6 christos static const char *
628 1.6 christos get_addrtype (int value)
629 1.1 christos {
630 1.6 christos if (value < 0 || value > addrtypenames_max)
631 1.6 christos return addrtypeunknown;
632 1.6 christos
633 1.6 christos return addrtypenames[value];
634 1.6 christos }
635 1.6 christos
636 1.6 christos /* Calculate the instruction length for an instruction starting with MSB
637 1.6 christos and LSB, the most and least significant byte. The ISA_MASK is used to
638 1.6 christos filter the instructions considered to only those that are part of the
639 1.6 christos current architecture.
640 1.6 christos
641 1.6 christos The instruction lengths are calculated from the ARC_OPCODE table, and
642 1.6 christos cached for later use. */
643 1.6 christos
644 1.6 christos static unsigned int
645 1.6 christos arc_insn_length (bfd_byte msb, bfd_byte lsb, struct disassemble_info *info)
646 1.6 christos {
647 1.6 christos bfd_byte major_opcode = msb >> 3;
648 1.1 christos
649 1.6 christos switch (info->mach)
650 1.1 christos {
651 1.6 christos case bfd_mach_arc_arc700:
652 1.6 christos /* The nps400 extension set requires this special casing of the
653 1.6 christos instruction length calculation. Right now this is not causing any
654 1.6 christos problems as none of the known extensions overlap in opcode space,
655 1.6 christos but, if they ever do then we might need to start carrying
656 1.6 christos information around in the elf about which extensions are in use. */
657 1.6 christos if (major_opcode == 0xb)
658 1.6 christos {
659 1.6 christos bfd_byte minor_opcode = lsb & 0x1f;
660 1.6 christos
661 1.7 christos if (minor_opcode < 4)
662 1.7 christos return 6;
663 1.7 christos else if (minor_opcode == 0x10 || minor_opcode == 0x11)
664 1.7 christos return 8;
665 1.6 christos }
666 1.7 christos if (major_opcode == 0xa)
667 1.7 christos {
668 1.7 christos return 8;
669 1.7 christos }
670 1.7 christos /* Fall through. */
671 1.6 christos case bfd_mach_arc_arc600:
672 1.6 christos return (major_opcode > 0xb) ? 2 : 4;
673 1.6 christos break;
674 1.6 christos
675 1.6 christos case bfd_mach_arc_arcv2:
676 1.6 christos return (major_opcode > 0x7) ? 2 : 4;
677 1.6 christos break;
678 1.6 christos
679 1.6 christos default:
680 1.9 christos return 0;
681 1.6 christos }
682 1.6 christos }
683 1.6 christos
684 1.6 christos /* Extract and return the value of OPERAND from the instruction whose value
685 1.6 christos is held in the array INSN. */
686 1.1 christos
687 1.6 christos static int
688 1.7 christos extract_operand_value (const struct arc_operand *operand,
689 1.7 christos unsigned long long insn,
690 1.7 christos unsigned limm)
691 1.6 christos {
692 1.6 christos int value;
693 1.1 christos
694 1.6 christos /* Read the limm operand, if required. */
695 1.6 christos if (operand->flags & ARC_OPERAND_LIMM)
696 1.6 christos /* The second part of the instruction value will have been loaded as
697 1.6 christos part of the find_format call made earlier. */
698 1.7 christos value = limm;
699 1.6 christos else
700 1.6 christos {
701 1.6 christos if (operand->extract)
702 1.9.2.1 perseant value = (*operand->extract) (insn, (bool *) NULL);
703 1.1 christos else
704 1.6 christos {
705 1.6 christos if (operand->flags & ARC_OPERAND_ALIGNED32)
706 1.6 christos {
707 1.7 christos value = (insn >> operand->shift)
708 1.6 christos & ((1 << (operand->bits - 2)) - 1);
709 1.6 christos value = value << 2;
710 1.6 christos }
711 1.6 christos else
712 1.6 christos {
713 1.7 christos value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
714 1.6 christos }
715 1.6 christos if (operand->flags & ARC_OPERAND_SIGNED)
716 1.6 christos {
717 1.6 christos int signbit = 1 << (operand->bits - 1);
718 1.6 christos value = (value ^ signbit) - signbit;
719 1.6 christos }
720 1.6 christos }
721 1.6 christos }
722 1.6 christos
723 1.6 christos return value;
724 1.6 christos }
725 1.6 christos
726 1.6 christos /* Find the next operand, and the operands value from ITER. Return TRUE if
727 1.6 christos there is another operand, otherwise return FALSE. If there is an
728 1.6 christos operand returned then the operand is placed into OPERAND, and the value
729 1.6 christos into VALUE. If there is no operand returned then OPERAND and VALUE are
730 1.6 christos unchanged. */
731 1.6 christos
732 1.9.2.1 perseant static bool
733 1.6 christos operand_iterator_next (struct arc_operand_iterator *iter,
734 1.6 christos const struct arc_operand **operand,
735 1.6 christos int *value)
736 1.6 christos {
737 1.7 christos if (*iter->opidx == 0)
738 1.6 christos {
739 1.7 christos *operand = NULL;
740 1.9.2.1 perseant return false;
741 1.6 christos }
742 1.1 christos
743 1.7 christos *operand = &arc_operands[*iter->opidx];
744 1.7 christos *value = extract_operand_value (*operand, iter->insn, iter->limm);
745 1.7 christos iter->opidx++;
746 1.6 christos
747 1.9.2.1 perseant return true;
748 1.6 christos }
749 1.6 christos
750 1.6 christos /* Helper for parsing the options. */
751 1.6 christos
752 1.6 christos static void
753 1.7 christos parse_option (const char *option)
754 1.6 christos {
755 1.8 christos if (disassembler_options_cmp (option, "dsp") == 0)
756 1.6 christos add_to_decodelist (DSP, NONE);
757 1.6 christos
758 1.8 christos else if (disassembler_options_cmp (option, "spfp") == 0)
759 1.6 christos add_to_decodelist (FLOAT, SPX);
760 1.1 christos
761 1.8 christos else if (disassembler_options_cmp (option, "dpfp") == 0)
762 1.6 christos add_to_decodelist (FLOAT, DPX);
763 1.1 christos
764 1.8 christos else if (disassembler_options_cmp (option, "quarkse_em") == 0)
765 1.7 christos {
766 1.7 christos add_to_decodelist (FLOAT, DPX);
767 1.7 christos add_to_decodelist (FLOAT, SPX);
768 1.8 christos add_to_decodelist (FLOAT, QUARKSE1);
769 1.8 christos add_to_decodelist (FLOAT, QUARKSE2);
770 1.7 christos }
771 1.6 christos
772 1.8 christos else if (disassembler_options_cmp (option, "fpuda") == 0)
773 1.6 christos add_to_decodelist (FLOAT, DPA);
774 1.6 christos
775 1.9 christos else if (disassembler_options_cmp (option, "nps400") == 0)
776 1.9 christos {
777 1.9 christos add_to_decodelist (ACL, NPS400);
778 1.9 christos add_to_decodelist (ARITH, NPS400);
779 1.9 christos add_to_decodelist (BITOP, NPS400);
780 1.9 christos add_to_decodelist (BMU, NPS400);
781 1.9 christos add_to_decodelist (CONTROL, NPS400);
782 1.9 christos add_to_decodelist (DMA, NPS400);
783 1.9 christos add_to_decodelist (DPI, NPS400);
784 1.9 christos add_to_decodelist (MEMORY, NPS400);
785 1.9 christos add_to_decodelist (MISC, NPS400);
786 1.9 christos add_to_decodelist (NET, NPS400);
787 1.9 christos add_to_decodelist (PMU, NPS400);
788 1.9 christos add_to_decodelist (PROTOCOL_DECODE, NPS400);
789 1.9 christos add_to_decodelist (ULTRAIP, NPS400);
790 1.9 christos }
791 1.9 christos
792 1.8 christos else if (disassembler_options_cmp (option, "fpus") == 0)
793 1.1 christos {
794 1.6 christos add_to_decodelist (FLOAT, SP);
795 1.6 christos add_to_decodelist (FLOAT, CVT);
796 1.1 christos }
797 1.1 christos
798 1.8 christos else if (disassembler_options_cmp (option, "fpud") == 0)
799 1.6 christos {
800 1.6 christos add_to_decodelist (FLOAT, DP);
801 1.6 christos add_to_decodelist (FLOAT, CVT);
802 1.6 christos }
803 1.9.2.1 perseant else if (startswith (option, "hex"))
804 1.9.2.1 perseant print_hex = true;
805 1.6 christos else
806 1.8 christos /* xgettext:c-format */
807 1.8 christos opcodes_error_handler (_("unrecognised disassembler option: %s"), option);
808 1.8 christos }
809 1.8 christos
810 1.8 christos #define ARC_CPU_TYPE_A6xx(NAME,EXTRA) \
811 1.8 christos { #NAME, ARC_OPCODE_ARC600, "ARC600" }
812 1.8 christos #define ARC_CPU_TYPE_A7xx(NAME,EXTRA) \
813 1.8 christos { #NAME, ARC_OPCODE_ARC700, "ARC700" }
814 1.8 christos #define ARC_CPU_TYPE_AV2EM(NAME,EXTRA) \
815 1.8 christos { #NAME, ARC_OPCODE_ARCv2EM, "ARC EM" }
816 1.8 christos #define ARC_CPU_TYPE_AV2HS(NAME,EXTRA) \
817 1.8 christos { #NAME, ARC_OPCODE_ARCv2HS, "ARC HS" }
818 1.8 christos #define ARC_CPU_TYPE_NONE \
819 1.8 christos { 0, 0, 0 }
820 1.8 christos
821 1.8 christos /* A table of CPU names and opcode sets. */
822 1.8 christos static const struct cpu_type
823 1.8 christos {
824 1.8 christos const char *name;
825 1.8 christos unsigned flags;
826 1.8 christos const char *isa;
827 1.8 christos }
828 1.8 christos cpu_types[] =
829 1.8 christos {
830 1.8 christos #include "elf/arc-cpu.def"
831 1.8 christos };
832 1.8 christos
833 1.8 christos /* Helper for parsing the CPU options. Accept any of the ARC architectures
834 1.8 christos values. OPTION should be a value passed to cpu=. */
835 1.8 christos
836 1.8 christos static unsigned
837 1.8 christos parse_cpu_option (const char *option)
838 1.8 christos {
839 1.8 christos int i;
840 1.8 christos
841 1.8 christos for (i = 0; cpu_types[i].name; ++i)
842 1.8 christos {
843 1.8 christos if (!disassembler_options_cmp (cpu_types[i].name, option))
844 1.8 christos {
845 1.8 christos return cpu_types[i].flags;
846 1.8 christos }
847 1.8 christos }
848 1.8 christos
849 1.8 christos /* xgettext:c-format */
850 1.8 christos opcodes_error_handler (_("unrecognised disassembler CPU option: %s"), option);
851 1.8 christos return ARC_OPCODE_NONE;
852 1.6 christos }
853 1.1 christos
854 1.6 christos /* Go over the options list and parse it. */
855 1.1 christos
856 1.6 christos static void
857 1.7 christos parse_disassembler_options (const char *options)
858 1.6 christos {
859 1.8 christos const char *option;
860 1.8 christos
861 1.6 christos if (options == NULL)
862 1.6 christos return;
863 1.6 christos
864 1.8 christos /* Disassembler might be reused for difference CPU's, and cpu option set for
865 1.8 christos the first one shouldn't be applied to second (which might not have
866 1.8 christos explicit cpu in its options. Therefore it is required to reset enforced
867 1.8 christos CPU when new options are being parsed. */
868 1.8 christos enforced_isa_mask = ARC_OPCODE_NONE;
869 1.8 christos
870 1.8 christos FOR_EACH_DISASSEMBLER_OPTION (option, options)
871 1.8 christos {
872 1.8 christos /* A CPU option? Cannot use STRING_COMMA_LEN because strncmp is also a
873 1.8 christos preprocessor macro. */
874 1.8 christos if (strncmp (option, "cpu=", 4) == 0)
875 1.8 christos /* Strip leading `cpu=`. */
876 1.8 christos enforced_isa_mask = parse_cpu_option (option + 4);
877 1.8 christos else
878 1.8 christos parse_option (option);
879 1.6 christos }
880 1.1 christos }
881 1.1 christos
882 1.7 christos /* Return the instruction type for an instruction described by OPCODE. */
883 1.7 christos
884 1.7 christos static enum dis_insn_type
885 1.7 christos arc_opcode_to_insn_type (const struct arc_opcode *opcode)
886 1.7 christos {
887 1.7 christos enum dis_insn_type insn_type;
888 1.7 christos
889 1.7 christos switch (opcode->insn_class)
890 1.7 christos {
891 1.7 christos case BRANCH:
892 1.7 christos case BBIT0:
893 1.7 christos case BBIT1:
894 1.7 christos case BI:
895 1.7 christos case BIH:
896 1.7 christos case BRCC:
897 1.7 christos case EI:
898 1.7 christos case JLI:
899 1.7 christos case JUMP:
900 1.7 christos case LOOP:
901 1.7 christos if (!strncmp (opcode->name, "bl", 2)
902 1.7 christos || !strncmp (opcode->name, "jl", 2))
903 1.7 christos {
904 1.7 christos if (opcode->subclass == COND)
905 1.7 christos insn_type = dis_condjsr;
906 1.7 christos else
907 1.7 christos insn_type = dis_jsr;
908 1.7 christos }
909 1.7 christos else
910 1.7 christos {
911 1.7 christos if (opcode->subclass == COND)
912 1.7 christos insn_type = dis_condbranch;
913 1.7 christos else
914 1.7 christos insn_type = dis_branch;
915 1.7 christos }
916 1.7 christos break;
917 1.7 christos case LOAD:
918 1.7 christos case STORE:
919 1.7 christos case MEMORY:
920 1.7 christos case ENTER:
921 1.7 christos case PUSH:
922 1.7 christos case POP:
923 1.7 christos insn_type = dis_dref;
924 1.7 christos break;
925 1.7 christos case LEAVE:
926 1.7 christos insn_type = dis_branch;
927 1.7 christos break;
928 1.7 christos default:
929 1.7 christos insn_type = dis_nonbranch;
930 1.7 christos break;
931 1.7 christos }
932 1.7 christos
933 1.7 christos return insn_type;
934 1.7 christos }
935 1.7 christos
936 1.6 christos /* Disassemble ARC instructions. */
937 1.1 christos
938 1.1 christos static int
939 1.6 christos print_insn_arc (bfd_vma memaddr,
940 1.6 christos struct disassemble_info *info)
941 1.1 christos {
942 1.7 christos bfd_byte buffer[8];
943 1.7 christos unsigned int highbyte, lowbyte;
944 1.6 christos int status;
945 1.6 christos unsigned int insn_len;
946 1.7 christos unsigned long long insn = 0;
947 1.8 christos unsigned isa_mask = ARC_OPCODE_NONE;
948 1.6 christos const struct arc_opcode *opcode;
949 1.9.2.1 perseant bool need_comma;
950 1.9.2.1 perseant bool open_braket;
951 1.6 christos int size;
952 1.6 christos const struct arc_operand *operand;
953 1.8 christos int value, vpcl;
954 1.6 christos struct arc_operand_iterator iter;
955 1.7 christos struct arc_disassemble_info *arc_infop;
956 1.9.2.1 perseant bool rpcl = false, rset = false;
957 1.6 christos
958 1.6 christos if (info->disassembler_options)
959 1.6 christos {
960 1.6 christos parse_disassembler_options (info->disassembler_options);
961 1.6 christos
962 1.6 christos /* Avoid repeated parsing of the options. */
963 1.6 christos info->disassembler_options = NULL;
964 1.6 christos }
965 1.6 christos
966 1.7 christos if (info->private_data == NULL && !init_arc_disasm_info (info))
967 1.7 christos return -1;
968 1.7 christos
969 1.6 christos memset (&iter, 0, sizeof (iter));
970 1.7 christos highbyte = ((info->endian == BFD_ENDIAN_LITTLE) ? 1 : 0);
971 1.7 christos lowbyte = ((info->endian == BFD_ENDIAN_LITTLE) ? 0 : 1);
972 1.6 christos
973 1.8 christos /* Figure out CPU type, unless it was enforced via disassembler options. */
974 1.8 christos if (enforced_isa_mask == ARC_OPCODE_NONE)
975 1.8 christos {
976 1.8 christos Elf_Internal_Ehdr *header = NULL;
977 1.8 christos
978 1.8 christos if (info->section && info->section->owner)
979 1.8 christos header = elf_elfheader (info->section->owner);
980 1.6 christos
981 1.8 christos switch (info->mach)
982 1.8 christos {
983 1.8 christos case bfd_mach_arc_arc700:
984 1.8 christos isa_mask = ARC_OPCODE_ARC700;
985 1.8 christos break;
986 1.1 christos
987 1.8 christos case bfd_mach_arc_arc600:
988 1.8 christos isa_mask = ARC_OPCODE_ARC600;
989 1.8 christos break;
990 1.1 christos
991 1.8 christos case bfd_mach_arc_arcv2:
992 1.8 christos default:
993 1.8 christos isa_mask = ARC_OPCODE_ARCv2EM;
994 1.8 christos /* TODO: Perhaps remove definition of header since it is only used at
995 1.8 christos this location. */
996 1.8 christos if (header != NULL
997 1.8 christos && (header->e_flags & EF_ARC_MACH_MSK) == EF_ARC_CPU_ARCV2HS)
998 1.8 christos isa_mask = ARC_OPCODE_ARCv2HS;
999 1.8 christos break;
1000 1.1 christos }
1001 1.8 christos }
1002 1.8 christos else
1003 1.8 christos isa_mask = enforced_isa_mask;
1004 1.8 christos
1005 1.8 christos if (isa_mask == ARC_OPCODE_ARCv2HS)
1006 1.8 christos {
1007 1.8 christos /* FPU instructions are not extensions for HS. */
1008 1.8 christos add_to_decodelist (FLOAT, SP);
1009 1.8 christos add_to_decodelist (FLOAT, DP);
1010 1.8 christos add_to_decodelist (FLOAT, CVT);
1011 1.6 christos }
1012 1.1 christos
1013 1.6 christos /* This variable may be set by the instruction decoder. It suggests
1014 1.6 christos the number of bytes objdump should display on a single line. If
1015 1.6 christos the instruction decoder sets this, it should always set it to
1016 1.6 christos the same value in order to get reasonable looking output. */
1017 1.6 christos info->bytes_per_line = 8;
1018 1.6 christos
1019 1.6 christos /* In the next lines, we set two info variables control the way
1020 1.6 christos objdump displays the raw data. For example, if bytes_per_line is
1021 1.6 christos 8 and bytes_per_chunk is 4, the output will look like this:
1022 1.6 christos 00: 00000000 00000000
1023 1.6 christos with the chunks displayed according to "display_endian". */
1024 1.6 christos if (info->section
1025 1.6 christos && !(info->section->flags & SEC_CODE))
1026 1.6 christos {
1027 1.6 christos /* This is not a CODE section. */
1028 1.6 christos switch (info->section->size)
1029 1.6 christos {
1030 1.6 christos case 1:
1031 1.6 christos case 2:
1032 1.6 christos case 4:
1033 1.6 christos size = info->section->size;
1034 1.1 christos break;
1035 1.1 christos default:
1036 1.6 christos size = (info->section->size & 0x01) ? 1 : 4;
1037 1.1 christos break;
1038 1.1 christos }
1039 1.6 christos info->bytes_per_chunk = 1;
1040 1.6 christos info->display_endian = info->endian;
1041 1.6 christos }
1042 1.6 christos else
1043 1.6 christos {
1044 1.6 christos size = 2;
1045 1.6 christos info->bytes_per_chunk = 2;
1046 1.6 christos info->display_endian = info->endian;
1047 1.6 christos }
1048 1.1 christos
1049 1.6 christos /* Read the insn into a host word. */
1050 1.6 christos status = (*info->read_memory_func) (memaddr, buffer, size, info);
1051 1.8 christos
1052 1.6 christos if (status != 0)
1053 1.6 christos {
1054 1.6 christos (*info->memory_error_func) (status, memaddr, info);
1055 1.6 christos return -1;
1056 1.6 christos }
1057 1.1 christos
1058 1.6 christos if (info->section
1059 1.6 christos && !(info->section->flags & SEC_CODE))
1060 1.6 christos {
1061 1.6 christos /* Data section. */
1062 1.6 christos unsigned long data;
1063 1.1 christos
1064 1.6 christos data = bfd_get_bits (buffer, size * 8,
1065 1.6 christos info->display_endian == BFD_ENDIAN_BIG);
1066 1.6 christos switch (size)
1067 1.1 christos {
1068 1.6 christos case 1:
1069 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream,
1070 1.9.2.1 perseant dis_style_assembler_directive,
1071 1.9.2.1 perseant ".byte");
1072 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_text, "\t");
1073 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
1074 1.9.2.1 perseant "0x%02lx", data);
1075 1.1 christos break;
1076 1.6 christos case 2:
1077 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream,
1078 1.9.2.1 perseant dis_style_assembler_directive,
1079 1.9.2.1 perseant ".short");
1080 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_text, "\t");
1081 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
1082 1.9.2.1 perseant "0x%04lx", data);
1083 1.1 christos break;
1084 1.6 christos case 4:
1085 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream,
1086 1.9.2.1 perseant dis_style_assembler_directive,
1087 1.9.2.1 perseant ".word");
1088 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_text, "\t");
1089 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
1090 1.9.2.1 perseant "0x%08lx", data);
1091 1.1 christos break;
1092 1.6 christos default:
1093 1.9 christos return -1;
1094 1.1 christos }
1095 1.6 christos return size;
1096 1.6 christos }
1097 1.1 christos
1098 1.7 christos insn_len = arc_insn_length (buffer[highbyte], buffer[lowbyte], info);
1099 1.6 christos pr_debug ("instruction length = %d bytes\n", insn_len);
1100 1.9 christos if (insn_len == 0)
1101 1.9 christos return -1;
1102 1.9 christos
1103 1.7 christos arc_infop = info->private_data;
1104 1.7 christos arc_infop->insn_len = insn_len;
1105 1.1 christos
1106 1.6 christos switch (insn_len)
1107 1.6 christos {
1108 1.6 christos case 2:
1109 1.7 christos insn = (buffer[highbyte] << 8) | buffer[lowbyte];
1110 1.1 christos break;
1111 1.1 christos
1112 1.6 christos case 4:
1113 1.7 christos {
1114 1.7 christos /* This is a long instruction: Read the remaning 2 bytes. */
1115 1.7 christos status = (*info->read_memory_func) (memaddr + 2, &buffer[2], 2, info);
1116 1.7 christos if (status != 0)
1117 1.7 christos {
1118 1.7 christos (*info->memory_error_func) (status, memaddr + 2, info);
1119 1.7 christos return -1;
1120 1.7 christos }
1121 1.7 christos insn = (unsigned long long) ARRANGE_ENDIAN (info, buffer);
1122 1.7 christos }
1123 1.7 christos break;
1124 1.7 christos
1125 1.7 christos case 6:
1126 1.7 christos {
1127 1.7 christos status = (*info->read_memory_func) (memaddr + 2, &buffer[2], 4, info);
1128 1.7 christos if (status != 0)
1129 1.7 christos {
1130 1.7 christos (*info->memory_error_func) (status, memaddr + 2, info);
1131 1.7 christos return -1;
1132 1.7 christos }
1133 1.7 christos insn = (unsigned long long) ARRANGE_ENDIAN (info, &buffer[2]);
1134 1.7 christos insn |= ((unsigned long long) buffer[highbyte] << 40)
1135 1.7 christos | ((unsigned long long) buffer[lowbyte] << 32);
1136 1.7 christos }
1137 1.7 christos break;
1138 1.7 christos
1139 1.7 christos case 8:
1140 1.7 christos {
1141 1.7 christos status = (*info->read_memory_func) (memaddr + 2, &buffer[2], 6, info);
1142 1.7 christos if (status != 0)
1143 1.7 christos {
1144 1.7 christos (*info->memory_error_func) (status, memaddr + 2, info);
1145 1.7 christos return -1;
1146 1.7 christos }
1147 1.7 christos insn =
1148 1.7 christos ((((unsigned long long) ARRANGE_ENDIAN (info, buffer)) << 32)
1149 1.7 christos | ((unsigned long long) ARRANGE_ENDIAN (info, &buffer[4])));
1150 1.7 christos }
1151 1.1 christos break;
1152 1.7 christos
1153 1.7 christos default:
1154 1.7 christos /* There is no instruction whose length is not 2, 4, 6, or 8. */
1155 1.9 christos return -1;
1156 1.1 christos }
1157 1.1 christos
1158 1.7 christos pr_debug ("instruction value = %llx\n", insn);
1159 1.7 christos
1160 1.6 christos /* Set some defaults for the insn info. */
1161 1.6 christos info->insn_info_valid = 1;
1162 1.6 christos info->branch_delay_insns = 0;
1163 1.7 christos info->data_size = 4;
1164 1.6 christos info->insn_type = dis_nonbranch;
1165 1.6 christos info->target = 0;
1166 1.6 christos info->target2 = 0;
1167 1.6 christos
1168 1.6 christos /* FIXME to be moved in dissasemble_init_for_target. */
1169 1.9.2.1 perseant info->disassembler_needs_relocs = true;
1170 1.6 christos
1171 1.6 christos /* Find the first match in the opcode table. */
1172 1.6 christos if (!find_format (memaddr, insn, &insn_len, isa_mask, info, &opcode, &iter))
1173 1.6 christos return -1;
1174 1.6 christos
1175 1.6 christos if (!opcode)
1176 1.6 christos {
1177 1.7 christos switch (insn_len)
1178 1.7 christos {
1179 1.7 christos case 2:
1180 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream,
1181 1.9.2.1 perseant dis_style_assembler_directive,
1182 1.9.2.1 perseant ".short");
1183 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_text, "\t");
1184 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
1185 1.9.2.1 perseant "0x%04llx", insn & 0xffff);
1186 1.7 christos break;
1187 1.9 christos
1188 1.7 christos case 4:
1189 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream,
1190 1.9.2.1 perseant dis_style_assembler_directive,
1191 1.9.2.1 perseant ".word");
1192 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_text, "\t");
1193 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
1194 1.9.2.1 perseant "0x%08llx", insn & 0xffffffff);
1195 1.7 christos break;
1196 1.9 christos
1197 1.7 christos case 6:
1198 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream,
1199 1.9.2.1 perseant dis_style_assembler_directive,
1200 1.9.2.1 perseant ".long");
1201 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_text, "\t");
1202 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
1203 1.9.2.1 perseant "0x%08llx", insn & 0xffffffff);
1204 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_text, " ");
1205 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
1206 1.9.2.1 perseant "0x%04llx", (insn >> 32) & 0xffff);
1207 1.7 christos break;
1208 1.9 christos
1209 1.7 christos case 8:
1210 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream,
1211 1.9.2.1 perseant dis_style_assembler_directive,
1212 1.9.2.1 perseant ".long");
1213 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_text, "\t");
1214 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
1215 1.9.2.1 perseant "0x%08llx", insn & 0xffffffff);
1216 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_text, " ");
1217 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
1218 1.9.2.1 perseant "0x%08llx", (insn >> 32));
1219 1.7 christos break;
1220 1.9 christos
1221 1.7 christos default:
1222 1.9 christos return -1;
1223 1.7 christos }
1224 1.6 christos
1225 1.6 christos info->insn_type = dis_noninsn;
1226 1.6 christos return insn_len;
1227 1.6 christos }
1228 1.6 christos
1229 1.6 christos /* Print the mnemonic. */
1230 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_mnemonic,
1231 1.9.2.1 perseant "%s", opcode->name);
1232 1.6 christos
1233 1.6 christos /* Preselect the insn class. */
1234 1.7 christos info->insn_type = arc_opcode_to_insn_type (opcode);
1235 1.6 christos
1236 1.7 christos pr_debug ("%s: 0x%08llx\n", opcode->name, opcode->opcode);
1237 1.1 christos
1238 1.7 christos print_flags (opcode, &insn, info);
1239 1.6 christos
1240 1.6 christos if (opcode->operands[0] != 0)
1241 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_text, "\t");
1242 1.1 christos
1243 1.9.2.1 perseant need_comma = false;
1244 1.9.2.1 perseant open_braket = false;
1245 1.7 christos arc_infop->operands_count = 0;
1246 1.1 christos
1247 1.6 christos /* Now extract and print the operands. */
1248 1.6 christos operand = NULL;
1249 1.8 christos vpcl = 0;
1250 1.6 christos while (operand_iterator_next (&iter, &operand, &value))
1251 1.6 christos {
1252 1.6 christos if (open_braket && (operand->flags & ARC_OPERAND_BRAKET))
1253 1.1 christos {
1254 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_text, "]");
1255 1.9.2.1 perseant open_braket = false;
1256 1.6 christos continue;
1257 1.1 christos }
1258 1.1 christos
1259 1.6 christos /* Only take input from real operands. */
1260 1.6 christos if (ARC_OPERAND_IS_FAKE (operand))
1261 1.6 christos continue;
1262 1.1 christos
1263 1.6 christos if ((operand->flags & ARC_OPERAND_IGNORE)
1264 1.6 christos && (operand->flags & ARC_OPERAND_IR)
1265 1.7 christos && value == -1)
1266 1.6 christos continue;
1267 1.1 christos
1268 1.6 christos if (operand->flags & ARC_OPERAND_COLON)
1269 1.7 christos {
1270 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_text, ":");
1271 1.7 christos continue;
1272 1.7 christos }
1273 1.1 christos
1274 1.6 christos if (need_comma)
1275 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_text,",");
1276 1.1 christos
1277 1.6 christos if (!open_braket && (operand->flags & ARC_OPERAND_BRAKET))
1278 1.1 christos {
1279 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_text, "[");
1280 1.9.2.1 perseant open_braket = true;
1281 1.9.2.1 perseant need_comma = false;
1282 1.6 christos continue;
1283 1.1 christos }
1284 1.6 christos
1285 1.9.2.1 perseant need_comma = true;
1286 1.6 christos
1287 1.8 christos if (operand->flags & ARC_OPERAND_PCREL)
1288 1.8 christos {
1289 1.9.2.1 perseant rpcl = true;
1290 1.8 christos vpcl = value;
1291 1.9.2.1 perseant rset = true;
1292 1.8 christos
1293 1.8 christos info->target = (bfd_vma) (memaddr & ~3) + value;
1294 1.8 christos }
1295 1.8 christos else if (!(operand->flags & ARC_OPERAND_IR))
1296 1.8 christos {
1297 1.8 christos vpcl = value;
1298 1.9.2.1 perseant rset = true;
1299 1.8 christos }
1300 1.8 christos
1301 1.6 christos /* Print the operand as directed by the flags. */
1302 1.6 christos if (operand->flags & ARC_OPERAND_IR)
1303 1.1 christos {
1304 1.6 christos const char *rname;
1305 1.6 christos
1306 1.6 christos assert (value >=0 && value < 64);
1307 1.6 christos rname = arcExtMap_coreRegName (value);
1308 1.6 christos if (!rname)
1309 1.6 christos rname = regnames[value];
1310 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_register,
1311 1.9.2.1 perseant "%s", rname);
1312 1.9 christos
1313 1.9 christos /* Check if we have a double register to print. */
1314 1.6 christos if (operand->flags & ARC_OPERAND_TRUNCATE)
1315 1.1 christos {
1316 1.9 christos if ((value & 0x01) == 0)
1317 1.9 christos {
1318 1.9 christos rname = arcExtMap_coreRegName (value + 1);
1319 1.9 christos if (!rname)
1320 1.9 christos rname = regnames[value + 1];
1321 1.9 christos }
1322 1.9 christos else
1323 1.9 christos rname = _("\nWarning: illegal use of double register "
1324 1.9 christos "pair.\n");
1325 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_register,
1326 1.9.2.1 perseant "%s", rname);
1327 1.1 christos }
1328 1.8 christos if (value == 63)
1329 1.9.2.1 perseant rpcl = true;
1330 1.8 christos else
1331 1.9.2.1 perseant rpcl = false;
1332 1.6 christos }
1333 1.6 christos else if (operand->flags & ARC_OPERAND_LIMM)
1334 1.6 christos {
1335 1.6 christos const char *rname = get_auxreg (opcode, value, isa_mask);
1336 1.6 christos
1337 1.6 christos if (rname && open_braket)
1338 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_register,
1339 1.9.2.1 perseant "%s", rname);
1340 1.1 christos else
1341 1.6 christos {
1342 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
1343 1.9.2.1 perseant "%#x", value);
1344 1.6 christos if (info->insn_type == dis_branch
1345 1.6 christos || info->insn_type == dis_jsr)
1346 1.6 christos info->target = (bfd_vma) value;
1347 1.6 christos }
1348 1.1 christos }
1349 1.6 christos else if (operand->flags & ARC_OPERAND_SIGNED)
1350 1.1 christos {
1351 1.6 christos const char *rname = get_auxreg (opcode, value, isa_mask);
1352 1.6 christos if (rname && open_braket)
1353 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_register,
1354 1.9.2.1 perseant "%s", rname);
1355 1.6 christos else
1356 1.8 christos {
1357 1.8 christos if (print_hex)
1358 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
1359 1.9.2.1 perseant "%#x", value);
1360 1.8 christos else
1361 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
1362 1.9.2.1 perseant "%d", value);
1363 1.8 christos }
1364 1.1 christos }
1365 1.6 christos else if (operand->flags & ARC_OPERAND_ADDRTYPE)
1366 1.7 christos {
1367 1.7 christos const char *addrtype = get_addrtype (value);
1368 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_address,
1369 1.9.2.1 perseant "%s", addrtype);
1370 1.7 christos /* A colon follow an address type. */
1371 1.9.2.1 perseant need_comma = false;
1372 1.7 christos }
1373 1.1 christos else
1374 1.1 christos {
1375 1.6 christos if (operand->flags & ARC_OPERAND_TRUNCATE
1376 1.6 christos && !(operand->flags & ARC_OPERAND_ALIGNED32)
1377 1.6 christos && !(operand->flags & ARC_OPERAND_ALIGNED16)
1378 1.8 christos && value >= 0 && value <= 14)
1379 1.8 christos {
1380 1.8 christos /* Leave/Enter mnemonics. */
1381 1.8 christos switch (value)
1382 1.8 christos {
1383 1.8 christos case 0:
1384 1.9.2.1 perseant need_comma = false;
1385 1.8 christos break;
1386 1.8 christos case 1:
1387 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream,
1388 1.9.2.1 perseant dis_style_register, "r13");
1389 1.8 christos break;
1390 1.8 christos default:
1391 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream,
1392 1.9.2.1 perseant dis_style_register, "r13");
1393 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream,
1394 1.9.2.1 perseant dis_style_text, "-");
1395 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream,
1396 1.9.2.1 perseant dis_style_register, "%s",
1397 1.9.2.1 perseant regnames[13 + value - 1]);
1398 1.8 christos break;
1399 1.8 christos }
1400 1.9.2.1 perseant rpcl = false;
1401 1.9.2.1 perseant rset = false;
1402 1.8 christos }
1403 1.6 christos else
1404 1.1 christos {
1405 1.6 christos const char *rname = get_auxreg (opcode, value, isa_mask);
1406 1.6 christos if (rname && open_braket)
1407 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_register,
1408 1.9.2.1 perseant "%s", rname);
1409 1.6 christos else
1410 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream, dis_style_immediate,
1411 1.9.2.1 perseant "%#x", value);
1412 1.1 christos }
1413 1.1 christos }
1414 1.7 christos
1415 1.7 christos if (operand->flags & ARC_OPERAND_LIMM)
1416 1.7 christos {
1417 1.7 christos arc_infop->operands[arc_infop->operands_count].kind
1418 1.7 christos = ARC_OPERAND_KIND_LIMM;
1419 1.7 christos /* It is not important to have exactly the LIMM indicator
1420 1.7 christos here. */
1421 1.7 christos arc_infop->operands[arc_infop->operands_count].value = 63;
1422 1.7 christos }
1423 1.7 christos else
1424 1.7 christos {
1425 1.7 christos arc_infop->operands[arc_infop->operands_count].value = value;
1426 1.7 christos arc_infop->operands[arc_infop->operands_count].kind
1427 1.7 christos = (operand->flags & ARC_OPERAND_IR
1428 1.7 christos ? ARC_OPERAND_KIND_REG
1429 1.7 christos : ARC_OPERAND_KIND_SHIMM);
1430 1.7 christos }
1431 1.7 christos arc_infop->operands_count ++;
1432 1.1 christos }
1433 1.1 christos
1434 1.8 christos /* Pretty print extra info for pc-relative operands. */
1435 1.8 christos if (rpcl && rset)
1436 1.8 christos {
1437 1.8 christos if (info->flags & INSN_HAS_RELOC)
1438 1.8 christos /* If the instruction has a reloc associated with it, then the
1439 1.8 christos offset field in the instruction will actually be the addend
1440 1.8 christos for the reloc. (We are using REL type relocs). In such
1441 1.8 christos cases, we can ignore the pc when computing addresses, since
1442 1.8 christos the addend is not currently pc-relative. */
1443 1.8 christos memaddr = 0;
1444 1.8 christos
1445 1.9.2.1 perseant (*info->fprintf_styled_func) (info->stream,
1446 1.9.2.1 perseant dis_style_comment_start, "\t;");
1447 1.8 christos (*info->print_address_func) ((memaddr & ~3) + vpcl, info);
1448 1.8 christos }
1449 1.8 christos
1450 1.6 christos return insn_len;
1451 1.1 christos }
1452 1.1 christos
1453 1.1 christos
1454 1.6 christos disassembler_ftype
1455 1.6 christos arc_get_disassembler (bfd *abfd)
1456 1.6 christos {
1457 1.7 christos /* BFD my be absent, if opcodes is invoked from the debugger that
1458 1.7 christos has connected to remote target and doesn't have an ELF file. */
1459 1.7 christos if (abfd != NULL)
1460 1.7 christos {
1461 1.7 christos /* Read the extension insns and registers, if any. */
1462 1.7 christos build_ARC_extmap (abfd);
1463 1.6 christos #ifdef DEBUG
1464 1.7 christos dump_ARC_extmap ();
1465 1.6 christos #endif
1466 1.7 christos }
1467 1.1 christos
1468 1.6 christos return print_insn_arc;
1469 1.1 christos }
1470 1.1 christos
1471 1.9.2.1 perseant /* Indices into option argument vector for options that do require
1472 1.9.2.1 perseant an argument. Use ARC_OPTION_ARG_NONE for options that don't
1473 1.9.2.1 perseant expect an argument. */
1474 1.9.2.1 perseant typedef enum
1475 1.9.2.1 perseant {
1476 1.9.2.1 perseant ARC_OPTION_ARG_NONE = -1,
1477 1.9.2.1 perseant ARC_OPTION_ARG_ARCH,
1478 1.9.2.1 perseant ARC_OPTION_ARG_SIZE
1479 1.9.2.1 perseant } arc_option_arg_t;
1480 1.9.2.1 perseant
1481 1.9.2.1 perseant /* Valid ARC disassembler options. */
1482 1.9.2.1 perseant static struct
1483 1.9.2.1 perseant {
1484 1.9.2.1 perseant const char *name;
1485 1.9.2.1 perseant const char *description;
1486 1.9.2.1 perseant arc_option_arg_t arg;
1487 1.9.2.1 perseant } arc_options[] =
1488 1.9.2.1 perseant {
1489 1.9.2.1 perseant { "cpu=", N_("Enforce the designated architecture while decoding."),
1490 1.9.2.1 perseant ARC_OPTION_ARG_ARCH },
1491 1.9.2.1 perseant { "dsp", N_("Recognize DSP instructions."),
1492 1.9.2.1 perseant ARC_OPTION_ARG_NONE },
1493 1.9.2.1 perseant { "spfp", N_("Recognize FPX SP instructions."),
1494 1.9.2.1 perseant ARC_OPTION_ARG_NONE },
1495 1.9.2.1 perseant { "dpfp", N_("Recognize FPX DP instructions."),
1496 1.9.2.1 perseant ARC_OPTION_ARG_NONE },
1497 1.9.2.1 perseant { "quarkse_em", N_("Recognize FPU QuarkSE-EM instructions."),
1498 1.9.2.1 perseant ARC_OPTION_ARG_NONE },
1499 1.9.2.1 perseant { "fpuda", N_("Recognize double assist FPU instructions."),
1500 1.9.2.1 perseant ARC_OPTION_ARG_NONE },
1501 1.9.2.1 perseant { "fpus", N_("Recognize single precision FPU instructions."),
1502 1.9.2.1 perseant ARC_OPTION_ARG_NONE },
1503 1.9.2.1 perseant { "fpud", N_("Recognize double precision FPU instructions."),
1504 1.9.2.1 perseant ARC_OPTION_ARG_NONE },
1505 1.9.2.1 perseant { "nps400", N_("Recognize NPS400 instructions."),
1506 1.9.2.1 perseant ARC_OPTION_ARG_NONE },
1507 1.9.2.1 perseant { "hex", N_("Use only hexadecimal number to print immediates."),
1508 1.9.2.1 perseant ARC_OPTION_ARG_NONE }
1509 1.9.2.1 perseant };
1510 1.9.2.1 perseant
1511 1.9.2.1 perseant /* Populate the structure for representing ARC's disassembly options.
1512 1.9.2.1 perseant Such a dynamic initialization is desired, because it makes the maintenance
1513 1.9.2.1 perseant easier and also gdb uses this to enable the "disassembler-option". */
1514 1.9.2.1 perseant
1515 1.9.2.1 perseant const disasm_options_and_args_t *
1516 1.9.2.1 perseant disassembler_options_arc (void)
1517 1.9.2.1 perseant {
1518 1.9.2.1 perseant static disasm_options_and_args_t *opts_and_args;
1519 1.9.2.1 perseant
1520 1.9.2.1 perseant if (opts_and_args == NULL)
1521 1.9.2.1 perseant {
1522 1.9.2.1 perseant disasm_option_arg_t *args;
1523 1.9.2.1 perseant disasm_options_t *opts;
1524 1.9.2.1 perseant size_t i;
1525 1.9.2.1 perseant const size_t nr_of_options = ARRAY_SIZE (arc_options);
1526 1.9.2.1 perseant /* There is a null element at the end of CPU_TYPES, therefore
1527 1.9.2.1 perseant NR_OF_CPUS is actually 1 more and that is desired here too. */
1528 1.9.2.1 perseant const size_t nr_of_cpus = ARRAY_SIZE (cpu_types);
1529 1.9.2.1 perseant
1530 1.9.2.1 perseant opts_and_args = XNEW (disasm_options_and_args_t);
1531 1.9.2.1 perseant opts_and_args->args
1532 1.9.2.1 perseant = XNEWVEC (disasm_option_arg_t, ARC_OPTION_ARG_SIZE + 1);
1533 1.9.2.1 perseant opts_and_args->options.name
1534 1.9.2.1 perseant = XNEWVEC (const char *, nr_of_options + 1);
1535 1.9.2.1 perseant opts_and_args->options.description
1536 1.9.2.1 perseant = XNEWVEC (const char *, nr_of_options + 1);
1537 1.9.2.1 perseant opts_and_args->options.arg
1538 1.9.2.1 perseant = XNEWVEC (const disasm_option_arg_t *, nr_of_options + 1);
1539 1.9.2.1 perseant
1540 1.9.2.1 perseant /* Populate the arguments for "cpu=" option. */
1541 1.9.2.1 perseant args = opts_and_args->args;
1542 1.9.2.1 perseant args[ARC_OPTION_ARG_ARCH].name = "ARCH";
1543 1.9.2.1 perseant args[ARC_OPTION_ARG_ARCH].values = XNEWVEC (const char *, nr_of_cpus);
1544 1.9.2.1 perseant for (i = 0; i < nr_of_cpus; ++i)
1545 1.9.2.1 perseant args[ARC_OPTION_ARG_ARCH].values[i] = cpu_types[i].name;
1546 1.9.2.1 perseant args[ARC_OPTION_ARG_SIZE].name = NULL;
1547 1.9.2.1 perseant args[ARC_OPTION_ARG_SIZE].values = NULL;
1548 1.9.2.1 perseant
1549 1.9.2.1 perseant /* Populate the options. */
1550 1.9.2.1 perseant opts = &opts_and_args->options;
1551 1.9.2.1 perseant for (i = 0; i < nr_of_options; ++i)
1552 1.9.2.1 perseant {
1553 1.9.2.1 perseant opts->name[i] = arc_options[i].name;
1554 1.9.2.1 perseant opts->description[i] = arc_options[i].description;
1555 1.9.2.1 perseant if (arc_options[i].arg != ARC_OPTION_ARG_NONE)
1556 1.9.2.1 perseant opts->arg[i] = &args[arc_options[i].arg];
1557 1.9.2.1 perseant else
1558 1.9.2.1 perseant opts->arg[i] = NULL;
1559 1.9.2.1 perseant }
1560 1.9.2.1 perseant opts->name[nr_of_options] = NULL;
1561 1.9.2.1 perseant opts->description[nr_of_options] = NULL;
1562 1.9.2.1 perseant opts->arg[nr_of_options] = NULL;
1563 1.9.2.1 perseant }
1564 1.9.2.1 perseant
1565 1.9.2.1 perseant return opts_and_args;
1566 1.9.2.1 perseant }
1567 1.9.2.1 perseant
1568 1.9.2.1 perseant
1569 1.6 christos void
1570 1.6 christos print_arc_disassembler_options (FILE *stream)
1571 1.1 christos {
1572 1.9.2.1 perseant const disasm_options_and_args_t *opts_and_args;
1573 1.9.2.1 perseant const disasm_option_arg_t *args;
1574 1.9.2.1 perseant const disasm_options_t *opts;
1575 1.9.2.1 perseant size_t i, j;
1576 1.9.2.1 perseant size_t max_len = 0;
1577 1.8 christos
1578 1.9.2.1 perseant opts_and_args = disassembler_options_arc ();
1579 1.9.2.1 perseant opts = &opts_and_args->options;
1580 1.9.2.1 perseant args = opts_and_args->args;
1581 1.6 christos
1582 1.9.2.1 perseant fprintf (stream, _("\nThe following ARC specific disassembler options are"
1583 1.9.2.1 perseant " supported for use \nwith the -M switch (multiple"
1584 1.9.2.1 perseant " options should be separated by commas):\n"));
1585 1.9.2.1 perseant
1586 1.9.2.1 perseant /* Find the maximum length for printing options (and their arg name). */
1587 1.9.2.1 perseant for (i = 0; opts->name[i] != NULL; ++i)
1588 1.8 christos {
1589 1.9.2.1 perseant size_t len = strlen (opts->name[i]);
1590 1.9.2.1 perseant len += (opts->arg[i]) ? strlen (opts->arg[i]->name) : 0;
1591 1.9.2.1 perseant max_len = (len > max_len) ? len : max_len;
1592 1.9.2.1 perseant }
1593 1.9.2.1 perseant
1594 1.9.2.1 perseant /* Print the options, their arg and description, if any. */
1595 1.9.2.1 perseant for (i = 0, ++max_len; opts->name[i] != NULL; ++i)
1596 1.9.2.1 perseant {
1597 1.9.2.1 perseant fprintf (stream, " %s", opts->name[i]);
1598 1.9.2.1 perseant if (opts->arg[i] != NULL)
1599 1.9.2.1 perseant fprintf (stream, "%s", opts->arg[i]->name);
1600 1.9.2.1 perseant if (opts->description[i] != NULL)
1601 1.9.2.1 perseant {
1602 1.9.2.1 perseant size_t len = strlen (opts->name[i]);
1603 1.9.2.1 perseant len += (opts->arg[i]) ? strlen (opts->arg[i]->name) : 0;
1604 1.9.2.1 perseant fprintf (stream,
1605 1.9.2.1 perseant "%*c %s", (int) (max_len - len), ' ', opts->description[i]);
1606 1.9.2.1 perseant }
1607 1.9.2.1 perseant fprintf (stream, _("\n"));
1608 1.9.2.1 perseant }
1609 1.9.2.1 perseant
1610 1.9.2.1 perseant /* Print the possible values of an argument. */
1611 1.9.2.1 perseant for (i = 0; args[i].name != NULL; ++i)
1612 1.9.2.1 perseant {
1613 1.9.2.1 perseant size_t len = 3;
1614 1.9.2.1 perseant if (args[i].values == NULL)
1615 1.9.2.1 perseant continue;
1616 1.9.2.1 perseant fprintf (stream, _("\n\
1617 1.9.2.1 perseant For the options above, the following values are supported for \"%s\":\n "),
1618 1.9.2.1 perseant args[i].name);
1619 1.9.2.1 perseant for (j = 0; args[i].values[j] != NULL; ++j)
1620 1.9.2.1 perseant {
1621 1.9.2.1 perseant fprintf (stream, " %s", args[i].values[j]);
1622 1.9.2.1 perseant len += strlen (args[i].values[j]) + 1;
1623 1.9.2.1 perseant /* reset line if printed too long. */
1624 1.9.2.1 perseant if (len >= 78)
1625 1.9.2.1 perseant {
1626 1.9.2.1 perseant fprintf (stream, _("\n "));
1627 1.9.2.1 perseant len = 3;
1628 1.9.2.1 perseant }
1629 1.9.2.1 perseant }
1630 1.9.2.1 perseant fprintf (stream, _("\n"));
1631 1.9.2.1 perseant }
1632 1.9.2.1 perseant
1633 1.9.2.1 perseant fprintf (stream, _("\n"));
1634 1.1 christos }
1635 1.1 christos
1636 1.7 christos void arc_insn_decode (bfd_vma addr,
1637 1.7 christos struct disassemble_info *info,
1638 1.7 christos disassembler_ftype disasm_func,
1639 1.7 christos struct arc_instruction *insn)
1640 1.7 christos {
1641 1.7 christos const struct arc_opcode *opcode;
1642 1.7 christos struct arc_disassemble_info *arc_infop;
1643 1.7 christos
1644 1.7 christos /* Ensure that insn would be in the reset state. */
1645 1.7 christos memset (insn, 0, sizeof (struct arc_instruction));
1646 1.7 christos
1647 1.7 christos /* There was an error when disassembling, for example memory read error. */
1648 1.7 christos if (disasm_func (addr, info) < 0)
1649 1.7 christos {
1650 1.9.2.1 perseant insn->valid = false;
1651 1.7 christos return;
1652 1.7 christos }
1653 1.7 christos
1654 1.7 christos assert (info->private_data != NULL);
1655 1.7 christos arc_infop = info->private_data;
1656 1.7 christos
1657 1.7 christos insn->length = arc_infop->insn_len;;
1658 1.7 christos insn->address = addr;
1659 1.7 christos
1660 1.7 christos /* Quick exit if memory at this address is not an instruction. */
1661 1.7 christos if (info->insn_type == dis_noninsn)
1662 1.7 christos {
1663 1.9.2.1 perseant insn->valid = false;
1664 1.7 christos return;
1665 1.7 christos }
1666 1.7 christos
1667 1.9.2.1 perseant insn->valid = true;
1668 1.7 christos
1669 1.7 christos opcode = (const struct arc_opcode *) arc_infop->opcode;
1670 1.7 christos insn->insn_class = opcode->insn_class;
1671 1.7 christos insn->limm_value = arc_infop->limm;
1672 1.7 christos insn->limm_p = arc_infop->limm_p;
1673 1.7 christos
1674 1.7 christos insn->is_control_flow = (info->insn_type == dis_branch
1675 1.7 christos || info->insn_type == dis_condbranch
1676 1.7 christos || info->insn_type == dis_jsr
1677 1.7 christos || info->insn_type == dis_condjsr);
1678 1.7 christos
1679 1.7 christos insn->has_delay_slot = info->branch_delay_insns;
1680 1.7 christos insn->writeback_mode
1681 1.7 christos = (enum arc_ldst_writeback_mode) arc_infop->writeback_mode;
1682 1.7 christos insn->data_size_mode = info->data_size;
1683 1.7 christos insn->condition_code = arc_infop->condition_code;
1684 1.7 christos memcpy (insn->operands, arc_infop->operands,
1685 1.7 christos sizeof (struct arc_insn_operand) * MAX_INSN_ARGS);
1686 1.7 christos insn->operands_count = arc_infop->operands_count;
1687 1.7 christos }
1688 1.1 christos
1689 1.6 christos /* Local variables:
1690 1.6 christos eval: (c-set-style "gnu")
1691 1.6 christos indent-tabs-mode: t
1692 1.6 christos End: */
1693