#include "config.h"
#endif
+#include "target.h"
#include "arm_disassembler.h"
#include "log.h"
{
instruction->type = ARM_SWI;
- snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSWI 0x%6.6" PRIx32 "", address, opcode, (opcode & 0xffffff));
+ snprintf(instruction->text, 128,
+ "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSVC %#6.6" PRIx32,
+ address, opcode, (opcode & 0xffffff));
return ERROR_OK;
}
if (U)
{
instruction->info.load_store_multiple.addressing_mode = 0;
- addressing_mode = "IA";
+ /* "IA" is the default in UAL syntax */
+ addressing_mode = "";
}
else
{
/* clear fields, to avoid confusion */
memset(instruction, 0, sizeof(arm_instruction_t));
instruction->opcode = opcode;
+ instruction->instruction_size = 4;
/* catch opcodes with condition field [31:28] = b1111 */
if ((opcode & 0xf0000000) == 0xf0000000)
mnemonic = "BL";
break;
}
- /* TODO: deals correctly with dual opcodes BL/BLX ... */
+
+ /* TODO: deal correctly with dual opcode (prefixed) BL/BLX;
+ * these are effectively 32-bit instructions even in Thumb1.
+ * Might be simplest to always use the Thumb2 decoder.
+ */
snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%4.4x\t%s 0x%8.8" PRIx32 , address, opcode,mnemonic, target_address);
if (L)
{
instruction->type = ARM_LDM;
- mnemonic = "LDMIA";
+ mnemonic = "LDM";
}
else
{
instruction->type = ARM_STM;
- mnemonic = "STMIA";
+ mnemonic = "STM";
}
snprintf(ptr_name,7,"r%i!, ",Rn);
}
if (cond == 0xf)
{
instruction->type = ARM_SWI;
- snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%4.4x\tSWI 0x%02" PRIx32 , address, opcode, offset);
+ snprintf(instruction->text, 128,
+ "0x%8.8" PRIx32 "\t0x%4.4x\tSVC 0x%02" PRIx32,
+ address, opcode, offset);
return ERROR_OK;
}
else if (cond == 0xe)
return ERROR_OK;
}
+static int evaluate_cb_thumb(uint16_t opcode, uint32_t address,
+ arm_instruction_t *instruction)
+{
+ unsigned offset;
+
+ /* added in Thumb2 */
+ offset = (opcode >> 3) & 0x1f;
+ offset |= (opcode & 0x0200) >> 4;
+
+ snprintf(instruction->text, 128,
+ "0x%8.8" PRIx32 "\t0x%4.4x\tCB%sZ r%d, %#8.8" PRIx32,
+ address, opcode,
+ (opcode & 0x0800) ? "N" : "",
+ opcode & 0x7, address + 4 + (offset << 1));
+
+ return ERROR_OK;
+}
+
+static int evaluate_extend_thumb(uint16_t opcode, uint32_t address,
+ arm_instruction_t *instruction)
+{
+ /* added in ARMv6 */
+ snprintf(instruction->text, 128,
+ "0x%8.8" PRIx32 "\t0x%4.4x\t%cXT%c r%d, r%d",
+ address, opcode,
+ (opcode & 0x0080) ? 'U' : 'S',
+ (opcode & 0x0040) ? 'B' : 'H',
+ opcode & 0x7, (opcode >> 3) & 0x7);
+
+ return ERROR_OK;
+}
+
+static int evaluate_cps_thumb(uint16_t opcode, uint32_t address,
+ arm_instruction_t *instruction)
+{
+ /* added in ARMv6 */
+ if ((opcode & 0x0ff0) == 0x0650)
+ snprintf(instruction->text, 128,
+ "0x%8.8" PRIx32 "\t0x%4.4x\tSETEND %s",
+ address, opcode,
+ (opcode & 0x80) ? "BE" : "LE");
+ else /* ASSUME (opcode & 0x0fe0) == 0x0660 */
+ snprintf(instruction->text, 128,
+ "0x%8.8" PRIx32 "\t0x%4.4x\tCPSI%c %s%s%s",
+ address, opcode,
+ (opcode & 0x0010) ? 'D' : 'E',
+ (opcode & 0x0004) ? "A" : "",
+ (opcode & 0x0002) ? "I" : "",
+ (opcode & 0x0001) ? "F" : "");
+
+ return ERROR_OK;
+}
+
+static int evaluate_byterev_thumb(uint16_t opcode, uint32_t address,
+ arm_instruction_t *instruction)
+{
+ char *suffix;
+
+ /* added in ARMv6 */
+ switch (opcode & 0x00c0) {
+ case 0:
+ suffix = "";
+ break;
+ case 1:
+ suffix = "16";
+ break;
+ default:
+ suffix = "SH";
+ break;
+ }
+ snprintf(instruction->text, 128,
+ "0x%8.8" PRIx32 "\t0x%4.4x\tREV%s r%d, r%d",
+ address, opcode, suffix,
+ opcode & 0x7, (opcode >> 3) & 0x7);
+
+ return ERROR_OK;
+}
+
+static int evaluate_hint_thumb(uint16_t opcode, uint32_t address,
+ arm_instruction_t *instruction)
+{
+ char *hint;
+
+ switch ((opcode >> 4) & 0x0f) {
+ case 0:
+ hint = "NOP";
+ break;
+ case 1:
+ hint = "YIELD";
+ break;
+ case 2:
+ hint = "WFE";
+ break;
+ case 3:
+ hint = "WFI";
+ break;
+ case 4:
+ hint = "SEV";
+ break;
+ default:
+ hint = "HINT (UNRECOGNIZED)";
+ break;
+ }
+
+ snprintf(instruction->text, 128,
+ "0x%8.8" PRIx32 "\t0x%4.4x\t%s",
+ address, opcode, hint);
+
+ return ERROR_OK;
+}
+
+static int evaluate_ifthen_thumb(uint16_t opcode, uint32_t address,
+ arm_instruction_t *instruction)
+{
+ unsigned cond = (opcode >> 4) & 0x0f;
+ char *x = "", *y = "", *z = "";
+
+ if (opcode & 0x01)
+ z = (opcode & 0x02) ? "T" : "E";
+ if (opcode & 0x03)
+ y = (opcode & 0x04) ? "T" : "E";
+ if (opcode & 0x07)
+ x = (opcode & 0x08) ? "T" : "E";
+
+ snprintf(instruction->text, 128,
+ "0x%8.8" PRIx32 "\t0x%4.4x\tIT%s%s%s %s",
+ address, opcode,
+ x, y, z, arm_condition_strings[cond]);
+
+ /* NOTE: strictly speaking, the next 1-4 instructions should
+ * now be displayed with the relevant conditional suffix...
+ */
+
+ return ERROR_OK;
+}
+
int thumb_evaluate_opcode(uint16_t opcode, uint32_t address, arm_instruction_t *instruction)
{
/* clear fields, to avoid confusion */
memset(instruction, 0, sizeof(arm_instruction_t));
instruction->opcode = opcode;
+ instruction->instruction_size = 2;
if ((opcode & 0xe000) == 0x0000)
{
/* Misc */
if ((opcode & 0xf000) == 0xb000)
{
- if ((opcode & 0x0f00) == 0x0000)
+ switch ((opcode >> 8) & 0x0f) {
+ case 0x0:
return evaluate_adjust_stack_thumb(opcode, address, instruction);
- else if ((opcode & 0x0f00) == 0x0e00)
+ case 0x1:
+ case 0x3:
+ case 0x9:
+ case 0xb:
+ return evaluate_cb_thumb(opcode, address, instruction);
+ case 0x2:
+ return evaluate_extend_thumb(opcode, address, instruction);
+ case 0x4:
+ case 0x5:
+ case 0xc:
+ case 0xd:
+ return evaluate_load_store_multiple_thumb(opcode, address,
+ instruction);
+ case 0x6:
+ return evaluate_cps_thumb(opcode, address, instruction);
+ case 0xa:
+ if ((opcode & 0x00c0) == 0x0080)
+ break;
+ return evaluate_byterev_thumb(opcode, address, instruction);
+ case 0xe:
return evaluate_breakpoint_thumb(opcode, address, instruction);
- else if ((opcode & 0x0600) == 0x0400) /* push pop */
- return evaluate_load_store_multiple_thumb(opcode, address, instruction);
- else
- {
- instruction->type = ARM_UNDEFINED_INSTRUCTION;
- snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%4.4x\tUNDEFINED INSTRUCTION", address, opcode);
- return ERROR_OK;
+ case 0xf:
+ if (opcode & 0x000f)
+ return evaluate_ifthen_thumb(opcode, address,
+ instruction);
+ else
+ return evaluate_hint_thumb(opcode, address,
+ instruction);
}
+
+ instruction->type = ARM_UNDEFINED_INSTRUCTION;
+ snprintf(instruction->text, 128,
+ "0x%8.8" PRIx32 "\t0x%4.4x\tUNDEFINED INSTRUCTION",
+ address, opcode);
+ return ERROR_OK;
}
/* Load/Store multiple */
return -1;
}
+/*
+ * REVISIT for Thumb2 instructions, instruction->type and friends aren't
+ * always set. That means eventual arm_simulate_step() support for Thumb2
+ * will need work in this area.
+ */
+int thumb2_opcode(target_t *target, uint32_t address, arm_instruction_t *instruction)
+{
+ int retval;
+ uint16_t op;
+ uint32_t opcode;
+
+ /* clear low bit ... it's set on function pointers */
+ address &= ~1;
+
+ /* clear fields, to avoid confusion */
+ memset(instruction, 0, sizeof(arm_instruction_t));
+
+ /* read first halfword, see if this is the only one */
+ retval = target_read_u16(target, address, &op);
+ if (retval != ERROR_OK)
+ return retval;
+
+ switch (op & 0xf800) {
+ case 0xf800:
+ case 0xf000:
+ case 0xe800:
+ /* 32-bit instructions */
+ instruction->instruction_size = 4;
+ opcode = op << 16;
+ retval = target_read_u16(target, address + 2, &op);
+ if (retval != ERROR_OK)
+ return retval;
+ opcode |= op;
+ instruction->opcode = opcode;
+ break;
+ default:
+ /* 16-bit: Thumb1 + IT + CBZ/CBNZ + ... */
+ return thumb_evaluate_opcode(op, address, instruction);
+ }
+
+ /* FIXME decode the 32-bit instructions */
+
+ LOG_DEBUG("Can't decode 32-bit Thumb2 yet (opcode=%08x)", opcode);
+
+ snprintf(instruction->text, 128,
+ "0x%8.8" PRIx32 "\t0x%8.8x\t... 32-bit Thumb2 ...",
+ address, opcode);
+ return ERROR_OK;
+}
+
int arm_access_size(arm_instruction_t *instruction)
{
if ((instruction->type == ARM_LDRB)
#include "cortex_m3.h"
#include "target_request.h"
#include "target_type.h"
+#include "arm_disassembler.h"
/* cli handling */
return ERROR_OK;
}
+/*
+ * REVISIT Thumb2 disassembly should work for all ARMv7 cores, as well
+ * as at least ARM-1156T2. The interesting thing about Cortex-M is
+ * that *only* Thumb2 disassembly matters. There are also some small
+ * additions to Thumb2 that are specific to ARMv7-M.
+ */
+static int
+handle_cortex_m3_disassemble_command(struct command_context_s *cmd_ctx,
+ char *cmd, char **args, int argc)
+{
+ int retval = ERROR_OK;
+ target_t *target = get_current_target(cmd_ctx);
+ uint32_t address;
+ unsigned long count;
+ arm_instruction_t cur_instruction;
+
+ if (argc != 2) {
+ command_print(cmd_ctx,
+ "usage: cortex_m3 disassemble <address> <count>");
+ return ERROR_OK;
+ }
+
+ errno = 0;
+ address = strtoul(args[0], NULL, 0);
+ if (errno)
+ return ERROR_FAIL;
+ count = strtoul(args[1], NULL, 0);
+ if (errno)
+ return ERROR_FAIL;
+
+ while (count--) {
+ retval = thumb2_opcode(target, address, &cur_instruction);
+ if (retval != ERROR_OK)
+ return retval;
+ command_print(cmd_ctx, "%s", cur_instruction.text);
+ address += cur_instruction.instruction_size;
+ }
+
+ return ERROR_OK;
+}
+
int cortex_m3_register_commands(struct command_context_s *cmd_ctx)
{
int retval;
retval = armv7m_register_commands(cmd_ctx);
- cortex_m3_cmd = register_command(cmd_ctx, NULL, "cortex_m3", NULL, COMMAND_ANY, "cortex_m3 specific commands");
- register_command(cmd_ctx, cortex_m3_cmd, "maskisr", handle_cortex_m3_mask_interrupts_command, COMMAND_EXEC, "mask cortex_m3 interrupts ['on'|'off']");
+ cortex_m3_cmd = register_command(cmd_ctx, NULL, "cortex_m3",
+ NULL, COMMAND_ANY, "cortex_m3 specific commands");
+
+ register_command(cmd_ctx, cortex_m3_cmd, "disassemble",
+ handle_cortex_m3_disassemble_command, COMMAND_EXEC,
+ "disassemble Thumb2 instructions <address> <count>");
+ register_command(cmd_ctx, cortex_m3_cmd, "maskisr",
+ handle_cortex_m3_mask_interrupts_command, COMMAND_EXEC,
+ "mask cortex_m3 interrupts ['on'|'off']");
return retval;
}