aboutsummaryrefslogtreecommitdiff
path: root/opcodes/arc-dis.c
diff options
context:
space:
mode:
Diffstat (limited to 'opcodes/arc-dis.c')
-rw-r--r--opcodes/arc-dis.c211
1 files changed, 174 insertions, 37 deletions
diff --git a/opcodes/arc-dis.c b/opcodes/arc-dis.c
index 53ba5f5..3afd253 100644
--- a/opcodes/arc-dis.c
+++ b/opcodes/arc-dis.c
@@ -51,6 +51,33 @@ struct arc_operand_iterator
const unsigned char *opidx;
};
+/* A private data used by ARC decoder. */
+struct arc_disassemble_info
+{
+ /* The current disassembled arc opcode. */
+ const struct arc_opcode *opcode;
+
+ /* Instruction length w/o limm field. */
+ unsigned insn_len;
+
+ /* TRUE if we have limm. */
+ bfd_boolean limm_p;
+
+ /* LIMM value, if exists. */
+ unsigned limm;
+
+ /* Condition code, if exists. */
+ unsigned condition_code;
+
+ /* Writeback mode. */
+ unsigned writeback_mode;
+
+ /* Number of operands. */
+ unsigned operands_count;
+
+ struct arc_insn_operand operands[MAX_INSN_ARGS];
+};
+
/* Globals variables. */
static const char * const regnames[64] =
@@ -108,6 +135,20 @@ static linkclass decodelist = NULL;
/* Functions implementation. */
+/* Initialize private data. */
+static bfd_boolean
+init_arc_disasm_info (struct disassemble_info *info)
+{
+ struct arc_disassemble_info *arc_infop
+ = calloc (sizeof (*arc_infop), 1);
+
+ if (arc_infop == NULL)
+ return FALSE;
+
+ info->private_data = arc_infop;
+ return TRUE;
+}
+
/* Add a new element to the decode list. */
static void
@@ -280,6 +321,10 @@ find_format_from_table (struct disassemble_info *info,
continue;
}
+ /* Check for the implicit flags. */
+ if (cl_flags->flag_class & F_CLASS_IMPLICIT)
+ continue;
+
for (flgopridx = cl_flags->flags; *flgopridx; ++flgopridx)
{
const struct arc_flag_operand *flg_operand =
@@ -367,6 +412,7 @@ find_format (bfd_vma memaddr,
bfd_boolean needs_limm;
const extInstruction_t *einsn, *i;
unsigned limm = 0;
+ struct arc_disassemble_info *arc_infop = info->private_data;
/* First, try the extension instructions. */
if (*insn_len == 4)
@@ -422,6 +468,12 @@ An error occured while generating the extension instruction operations");
}
*opcode_result = opcode;
+
+ /* Update private data. */
+ arc_infop->opcode = opcode;
+ arc_infop->limm = (needs_limm) ? limm : 0;
+ arc_infop->limm_p = needs_limm;
+
return TRUE;
}
@@ -432,6 +484,7 @@ print_flags (const struct arc_opcode *opcode,
{
const unsigned char *flgidx;
unsigned int value;
+ struct arc_disassemble_info *arc_infop = info->private_data;
/* Now extract and print the flags. */
for (flgidx = opcode->flags; *flgidx; flgidx++)
@@ -459,6 +512,18 @@ print_flags (const struct arc_opcode *opcode,
const struct arc_flag_operand *flg_operand =
&arc_flag_operands[*flgopridx];
+ /* Implicit flags are only used for the insn decoder. */
+ if (cl_flags->flag_class & F_CLASS_IMPLICIT)
+ {
+ if (cl_flags->flag_class & F_CLASS_COND)
+ arc_infop->condition_code = flg_operand->code;
+ else if (cl_flags->flag_class & F_CLASS_WB)
+ arc_infop->writeback_mode = flg_operand->code;
+ else if (cl_flags->flag_class & F_CLASS_ZZ)
+ info->data_size = flg_operand->code;
+ continue;
+ }
+
if (!flg_operand->favail)
continue;
@@ -496,8 +561,13 @@ print_flags (const struct arc_opcode *opcode,
info->insn_type = dis_condjsr;
else if (info->insn_type == dis_branch)
info->insn_type = dis_condbranch;
+ arc_infop->condition_code = flg_operand->code;
}
+ /* Check for the write back modes. */
+ if (cl_flags->flag_class & F_CLASS_WB)
+ arc_infop->writeback_mode = flg_operand->code;
+
(*info->fprintf_func) (info->stream, "%s", flg_operand->name);
}
}
@@ -733,7 +803,15 @@ arc_opcode_to_insn_type (const struct arc_opcode *opcode)
switch (opcode->insn_class)
{
case BRANCH:
+ case BBIT0:
+ case BBIT1:
+ case BI:
+ case BIH:
+ case BRCC:
+ case EI:
+ case JLI:
case JUMP:
+ case LOOP:
if (!strncmp (opcode->name, "bl", 2)
|| !strncmp (opcode->name, "jl", 2))
{
@@ -753,8 +831,14 @@ arc_opcode_to_insn_type (const struct arc_opcode *opcode)
case LOAD:
case STORE:
case MEMORY:
+ case ENTER:
+ case PUSH:
+ case POP:
insn_type = dis_dref;
break;
+ case LEAVE:
+ insn_type = dis_branch;
+ break;
default:
insn_type = dis_nonbranch;
break;
@@ -783,6 +867,7 @@ print_insn_arc (bfd_vma memaddr,
int value;
struct arc_operand_iterator iter;
Elf_Internal_Ehdr *header = NULL;
+ struct arc_disassemble_info *arc_infop;
if (info->disassembler_options)
{
@@ -792,6 +877,9 @@ print_insn_arc (bfd_vma memaddr,
info->disassembler_options = NULL;
}
+ if (info->private_data == NULL && !init_arc_disasm_info (info))
+ return -1;
+
memset (&iter, 0, sizeof (iter));
highbyte = ((info->endian == BFD_ENDIAN_LITTLE) ? 1 : 0);
lowbyte = ((info->endian == BFD_ENDIAN_LITTLE) ? 0 : 1);
@@ -813,7 +901,7 @@ print_insn_arc (bfd_vma memaddr,
default:
isa_mask = ARC_OPCODE_ARCv2EM;
/* TODO: Perhaps remove defitinion of header since it is only used at
- this location. */
+ this location. */
if (header != NULL
&& (header->e_flags & EF_ARC_MACH_MSK) == EF_ARC_CPU_ARCV2HS)
{
@@ -899,6 +987,8 @@ print_insn_arc (bfd_vma memaddr,
insn_len = arc_insn_length (buffer[highbyte], buffer[lowbyte], info);
pr_debug ("instruction length = %d bytes\n", insn_len);
+ arc_infop = info->private_data;
+ arc_infop->insn_len = insn_len;
switch (insn_len)
{
@@ -957,7 +1047,7 @@ print_insn_arc (bfd_vma memaddr,
/* Set some defaults for the insn info. */
info->insn_info_valid = 1;
info->branch_delay_insns = 0;
- info->data_size = 0;
+ info->data_size = 4;
info->insn_type = dis_nonbranch;
info->target = 0;
info->target2 = 0;
@@ -1016,6 +1106,7 @@ print_insn_arc (bfd_vma memaddr,
need_comma = FALSE;
open_braket = FALSE;
+ arc_infop->operands_count = 0;
/* Now extract and print the operands. */
operand = NULL;
@@ -1034,14 +1125,14 @@ print_insn_arc (bfd_vma memaddr,
if ((operand->flags & ARC_OPERAND_IGNORE)
&& (operand->flags & ARC_OPERAND_IR)
- && value == -1)
+ && value == -1)
continue;
if (operand->flags & ARC_OPERAND_COLON)
- {
- (*info->fprintf_func) (info->stream, ":");
- continue;
- }
+ {
+ (*info->fprintf_func) (info->stream, ":");
+ continue;
+ }
if (need_comma)
(*info->fprintf_func) (info->stream, ",");
@@ -1106,12 +1197,12 @@ print_insn_arc (bfd_vma memaddr,
(*info->fprintf_func) (info->stream, "%d", value);
}
else if (operand->flags & ARC_OPERAND_ADDRTYPE)
- {
- const char *addrtype = get_addrtype (value);
- (*info->fprintf_func) (info->stream, "%s", addrtype);
- /* A colon follow an address type. */
- need_comma = FALSE;
- }
+ {
+ const char *addrtype = get_addrtype (value);
+ (*info->fprintf_func) (info->stream, "%s", addrtype);
+ /* A colon follow an address type. */
+ need_comma = FALSE;
+ }
else
{
if (operand->flags & ARC_OPERAND_TRUNCATE
@@ -1129,6 +1220,24 @@ print_insn_arc (bfd_vma memaddr,
(*info->fprintf_func) (info->stream, "%#x", value);
}
}
+
+ if (operand->flags & ARC_OPERAND_LIMM)
+ {
+ arc_infop->operands[arc_infop->operands_count].kind
+ = ARC_OPERAND_KIND_LIMM;
+ /* It is not important to have exactly the LIMM indicator
+ here. */
+ arc_infop->operands[arc_infop->operands_count].value = 63;
+ }
+ else
+ {
+ arc_infop->operands[arc_infop->operands_count].value = value;
+ arc_infop->operands[arc_infop->operands_count].kind
+ = (operand->flags & ARC_OPERAND_IR
+ ? ARC_OPERAND_KIND_REG
+ : ARC_OPERAND_KIND_SHIMM);
+ }
+ arc_infop->operands_count ++;
}
return insn_len;
@@ -1152,30 +1261,6 @@ arc_get_disassembler (bfd *abfd)
return print_insn_arc;
}
-/* Disassemble ARC instructions. Used by debugger. */
-
-struct arcDisState
-arcAnalyzeInstr (bfd_vma memaddr,
- struct disassemble_info *info)
-{
- struct arcDisState ret;
- memset (&ret, 0, sizeof (struct arcDisState));
-
- ret.instructionLen = print_insn_arc (memaddr, info);
-
-#if 0
- ret.words[0] = insn[0];
- ret.words[1] = insn[1];
- ret._this = &ret;
- ret.coreRegName = _coreRegName;
- ret.auxRegName = _auxRegName;
- ret.condCodeName = _condCodeName;
- ret.instName = _instName;
-#endif
-
- return ret;
-}
-
void
print_arc_disassembler_options (FILE *stream)
{
@@ -1199,6 +1284,58 @@ with -M switch (multiple options should be separated by commas):\n"));
fpud Recognize double precision FPU instructions.\n"));
}
+void arc_insn_decode (bfd_vma addr,
+ struct disassemble_info *info,
+ disassembler_ftype disasm_func,
+ struct arc_instruction *insn)
+{
+ const struct arc_opcode *opcode;
+ struct arc_disassemble_info *arc_infop;
+
+ /* Ensure that insn would be in the reset state. */
+ memset (insn, 0, sizeof (struct arc_instruction));
+
+ /* There was an error when disassembling, for example memory read error. */
+ if (disasm_func (addr, info) < 0)
+ {
+ insn->valid = FALSE;
+ return;
+ }
+
+ assert (info->private_data != NULL);
+ arc_infop = info->private_data;
+
+ insn->length = arc_infop->insn_len;;
+ insn->address = addr;
+
+ /* Quick exit if memory at this address is not an instruction. */
+ if (info->insn_type == dis_noninsn)
+ {
+ insn->valid = FALSE;
+ return;
+ }
+
+ insn->valid = TRUE;
+
+ opcode = (const struct arc_opcode *) arc_infop->opcode;
+ insn->insn_class = opcode->insn_class;
+ insn->limm_value = arc_infop->limm;
+ insn->limm_p = arc_infop->limm_p;
+
+ insn->is_control_flow = (info->insn_type == dis_branch
+ || info->insn_type == dis_condbranch
+ || info->insn_type == dis_jsr
+ || info->insn_type == dis_condjsr);
+
+ insn->has_delay_slot = info->branch_delay_insns;
+ insn->writeback_mode
+ = (enum arc_ldst_writeback_mode) arc_infop->writeback_mode;
+ insn->data_size_mode = info->data_size;
+ insn->condition_code = arc_infop->condition_code;
+ memcpy (insn->operands, arc_infop->operands,
+ sizeof (struct arc_insn_operand) * MAX_INSN_ARGS);
+ insn->operands_count = arc_infop->operands_count;
+}
/* Local variables:
eval: (c-set-style "gnu")