/* Instruction printing code for the ARM
Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
- 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+ 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
Modification by James G. Smith (jsmith@cygnus.co.uk)
#define NUM_ELEM(a) (sizeof (a) / sizeof (a)[0])
#endif
+struct arm_private_data
+{
+ /* The features to use when disassembling optional instructions. */
+ arm_feature_set features;
+
+ /* Whether any mapping symbols are present in the provided symbol
+ table. -1 if we do not know yet, otherwise 0 or 1. */
+ int has_mapping_symbols;
+};
+
struct opcode32
{
unsigned long arch; /* Architecture defining this insn. */
{ARM_EXT_V5E, 0x0c400000, 0x0ff00000, "mcrr%c\t%8-11d, %4-7d, %12-15R, %16-19r, cr%0-3d"},
{ARM_EXT_V5E, 0x0c500000, 0x0ff00000, "mrrc%c\t%8-11d, %4-7d, %12-15Ru, %16-19Ru, cr%0-3d"},
{ARM_EXT_V2, 0x0e000000, 0x0f000010, "cdp%c\t%8-11d, %20-23d, cr%12-15d, cr%16-19d, cr%0-3d, {%5-7d}"},
+ {ARM_EXT_V2, 0x0e10f010, 0x0f10f010, "mrc%c\t%8-11d, %21-23d, APSR_nzcv, cr%16-19d, cr%0-3d, {%5-7d}"},
{ARM_EXT_V2, 0x0e100010, 0x0f100010, "mrc%c\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"},
{ARM_EXT_V2, 0x0e000010, 0x0f100010, "mcr%c\t%8-11d, %21-23d, %12-15R, cr%16-19d, cr%0-3d, {%5-7d}"},
{ARM_EXT_V2, 0x0c000000, 0x0e100000, "stc%22'l%c\t%8-11d, cr%12-15d, %A"},
%e print arm SMI operand (bits 0..7,8..19).
%E print the LSB and WIDTH fields of a BFI or BFC instruction.
- %V print the 16-bit immediate field of a MOVT or MOVW instruction. */
+ %V print the 16-bit immediate field of a MOVT or MOVW instruction.
+ %R print the SPSR/CPSR or banked register of an MRS. */
static const struct opcode32 arm_opcodes[] =
{
{ARM_EXT_V3M, 0x00800090, 0x0fa000f0, "%22?sumull%20's%c\t%12-15Ru, %16-19Ru, %0-3R, %8-11R"},
{ARM_EXT_V3M, 0x00a00090, 0x0fa000f0, "%22?sumlal%20's%c\t%12-15Ru, %16-19Ru, %0-3R, %8-11R"},
+ /* Virtualization Extension instructions. */
+ {ARM_EXT_VIRT, 0x0160006e, 0x0fffffff, "eret%c"},
+ {ARM_EXT_VIRT, 0x01400070, 0x0ff000f0, "hvc%c\t%e"},
+
+ /* Integer Divide Extension instructions. */
+ {ARM_EXT_ADIV, 0x0710f010, 0x0ff0f0f0, "sdiv%c\t%16-19r, %0-3r, %8-11r"},
+ {ARM_EXT_ADIV, 0x0730f010, 0x0ff0f0f0, "udiv%c\t%16-19r, %0-3r, %8-11r"},
+
+ /* MP Extension instructions. */
+ {ARM_EXT_MP, 0xf410f000, 0xfc70f000, "pldw\t%a"},
+
/* V7 instructions. */
{ARM_EXT_V7, 0xf450f000, 0xfd70f000, "pli\t%P"},
{ARM_EXT_V7, 0x0320f0f0, 0x0ffffff0, "dbg%c\t#%0-3d"},
{ARM_EXT_V6T2, 0x06ff0f30, 0x0fff0ff0, "rbit%c\t%12-15R, %0-3R"},
{ARM_EXT_V6T2, 0x07a00050, 0x0fa00070, "%22?usbfx%c\t%12-15r, %0-3r, #%7-11d, #%16-20W"},
- /* ARM V6Z instructions. */
- {ARM_EXT_V6Z, 0x01600070, 0x0ff000f0, "smc%c\t%e"},
+ /* ARM Security extension instructions. */
+ {ARM_EXT_SEC, 0x01600070, 0x0ff000f0, "smc%c\t%e"},
/* ARM V6K instructions. */
{ARM_EXT_V6K, 0xf57ff01f, 0xffffffff, "clrex"},
{ARM_EXT_V6, 0x01900f9f, 0x0ff00fff, "ldrex%c\tr%12-15d, [%16-19R]"},
{ARM_EXT_V6, 0x06200f10, 0x0ff00ff0, "qadd16%c\t%12-15R, %16-19R, %0-3R"},
{ARM_EXT_V6, 0x06200f90, 0x0ff00ff0, "qadd8%c\t%12-15R, %16-19R, %0-3R"},
- {ARM_EXT_V6, 0x06200f30, 0x0ff00ff0, "qaddsubx%c\t%12-15R, %16-19R, %0-3R"},
+ {ARM_EXT_V6, 0x06200f30, 0x0ff00ff0, "qasx%c\t%12-15R, %16-19R, %0-3R"},
{ARM_EXT_V6, 0x06200f70, 0x0ff00ff0, "qsub16%c\t%12-15R, %16-19R, %0-3R"},
{ARM_EXT_V6, 0x06200ff0, 0x0ff00ff0, "qsub8%c\t%12-15R, %16-19R, %0-3R"},
- {ARM_EXT_V6, 0x06200f50, 0x0ff00ff0, "qsubaddx%c\t%12-15R, %16-19R, %0-3R"},
+ {ARM_EXT_V6, 0x06200f50, 0x0ff00ff0, "qsax%c\t%12-15R, %16-19R, %0-3R"},
{ARM_EXT_V6, 0x06100f10, 0x0ff00ff0, "sadd16%c\t%12-15R, %16-19R, %0-3R"},
{ARM_EXT_V6, 0x06100f90, 0x0ff00ff0, "sadd8%c\t%12-15R, %16-19R, %0-3R"},
- {ARM_EXT_V6, 0x06100f30, 0x0ff00ff0, "saddaddx%c\t%12-15R, %16-19R, %0-3R"},
+ {ARM_EXT_V6, 0x06100f30, 0x0ff00ff0, "sasx%c\t%12-15R, %16-19R, %0-3R"},
{ARM_EXT_V6, 0x06300f10, 0x0ff00ff0, "shadd16%c\t%12-15R, %16-19R, %0-3R"},
{ARM_EXT_V6, 0x06300f90, 0x0ff00ff0, "shadd8%c\t%12-15R, %16-19R, %0-3R"},
- {ARM_EXT_V6, 0x06300f30, 0x0ff00ff0, "shaddsubx%c\t%12-15R, %16-19R, %0-3R"},
+ {ARM_EXT_V6, 0x06300f30, 0x0ff00ff0, "shasx%c\t%12-15R, %16-19R, %0-3R"},
{ARM_EXT_V6, 0x06300f70, 0x0ff00ff0, "shsub16%c\t%12-15R, %16-19R, %0-3R"},
{ARM_EXT_V6, 0x06300ff0, 0x0ff00ff0, "shsub8%c\t%12-15R, %16-19R, %0-3R"},
- {ARM_EXT_V6, 0x06300f50, 0x0ff00ff0, "shsubaddx%c\t%12-15R, %16-19R, %0-3R"},
+ {ARM_EXT_V6, 0x06300f50, 0x0ff00ff0, "shsax%c\t%12-15R, %16-19R, %0-3R"},
{ARM_EXT_V6, 0x06100f70, 0x0ff00ff0, "ssub16%c\t%12-15R, %16-19R, %0-3R"},
{ARM_EXT_V6, 0x06100ff0, 0x0ff00ff0, "ssub8%c\t%12-15R, %16-19R, %0-3R"},
- {ARM_EXT_V6, 0x06100f50, 0x0ff00ff0, "ssubaddx%c\t%12-15R, %16-19R, %0-3R"},
+ {ARM_EXT_V6, 0x06100f50, 0x0ff00ff0, "ssax%c\t%12-15R, %16-19R, %0-3R"},
{ARM_EXT_V6, 0x06500f10, 0x0ff00ff0, "uadd16%c\t%12-15R, %16-19R, %0-3R"},
{ARM_EXT_V6, 0x06500f90, 0x0ff00ff0, "uadd8%c\t%12-15R, %16-19R, %0-3R"},
- {ARM_EXT_V6, 0x06500f30, 0x0ff00ff0, "uaddsubx%c\t%12-15R, %16-19R, %0-3R"},
+ {ARM_EXT_V6, 0x06500f30, 0x0ff00ff0, "uasx%c\t%12-15R, %16-19R, %0-3R"},
{ARM_EXT_V6, 0x06700f10, 0x0ff00ff0, "uhadd16%c\t%12-15R, %16-19R, %0-3R"},
{ARM_EXT_V6, 0x06700f90, 0x0ff00ff0, "uhadd8%c\t%12-15R, %16-19R, %0-3R"},
- {ARM_EXT_V6, 0x06700f30, 0x0ff00ff0, "uhaddsubx%c\t%12-15R, %16-19R, %0-3R"},
+ {ARM_EXT_V6, 0x06700f30, 0x0ff00ff0, "uhasx%c\t%12-15R, %16-19R, %0-3R"},
{ARM_EXT_V6, 0x06700f70, 0x0ff00ff0, "uhsub16%c\t%12-15R, %16-19R, %0-3R"},
{ARM_EXT_V6, 0x06700ff0, 0x0ff00ff0, "uhsub8%c\t%12-15R, %16-19R, %0-3R"},
- {ARM_EXT_V6, 0x06700f50, 0x0ff00ff0, "uhsubaddx%c\t%12-15R, %16-19R, %0-3R"},
+ {ARM_EXT_V6, 0x06700f50, 0x0ff00ff0, "uhsax%c\t%12-15R, %16-19R, %0-3R"},
{ARM_EXT_V6, 0x06600f10, 0x0ff00ff0, "uqadd16%c\t%12-15R, %16-19R, %0-3R"},
{ARM_EXT_V6, 0x06600f90, 0x0ff00ff0, "uqadd8%c\t%12-15R, %16-19R, %0-3R"},
- {ARM_EXT_V6, 0x06600f30, 0x0ff00ff0, "uqaddsubx%c\t%12-15R, %16-19R, %0-3R"},
+ {ARM_EXT_V6, 0x06600f30, 0x0ff00ff0, "uqasx%c\t%12-15R, %16-19R, %0-3R"},
{ARM_EXT_V6, 0x06600f70, 0x0ff00ff0, "uqsub16%c\t%12-15R, %16-19R, %0-3R"},
{ARM_EXT_V6, 0x06600ff0, 0x0ff00ff0, "uqsub8%c\t%12-15R, %16-19R, %0-3R"},
- {ARM_EXT_V6, 0x06600f50, 0x0ff00ff0, "uqsubaddx%c\t%12-15R, %16-19R, %0-3R"},
+ {ARM_EXT_V6, 0x06600f50, 0x0ff00ff0, "uqsax%c\t%12-15R, %16-19R, %0-3R"},
{ARM_EXT_V6, 0x06500f70, 0x0ff00ff0, "usub16%c\t%12-15R, %16-19R, %0-3R"},
{ARM_EXT_V6, 0x06500ff0, 0x0ff00ff0, "usub8%c\t%12-15R, %16-19R, %0-3R"},
- {ARM_EXT_V6, 0x06500f50, 0x0ff00ff0, "usubaddx%c\t%12-15R, %16-19R, %0-3R"},
+ {ARM_EXT_V6, 0x06500f50, 0x0ff00ff0, "usax%c\t%12-15R, %16-19R, %0-3R"},
{ARM_EXT_V6, 0x06bf0f30, 0x0fff0ff0, "rev%c\t%12-15R, %0-3R"},
{ARM_EXT_V6, 0x06bf0fb0, 0x0fff0ff0, "rev16%c\t%12-15R, %0-3R"},
{ARM_EXT_V6, 0x06ff0fb0, 0x0fff0ff0, "revsh%c\t%12-15R, %0-3R"},
{ARM_EXT_V1, 0x00e00000, 0x0fe00010, "rsc%20's%c\t%12-15r, %16-19r, %o"},
{ARM_EXT_V1, 0x00e00010, 0x0fe00090, "rsc%20's%c\t%12-15R, %16-19R, %o"},
- {ARM_EXT_V3, 0x0120f000, 0x0db0f000, "msr%c\t%22?SCPSR%C, %o"},
- {ARM_EXT_V3, 0x010f0000, 0x0fbf0fff, "mrs%c\t%12-15R, %22?SCPSR"},
+ {ARM_EXT_VIRT, 0x0120f200, 0x0fb0f200, "msr%c\t%C, %0-3r"},
+ {ARM_EXT_V3, 0x0120f000, 0x0db0f000, "msr%c\t%C, %o"},
+ {ARM_EXT_V3, 0x01000000, 0x0fb00cff, "mrs%c\t%12-15R, %R"},
{ARM_EXT_V1, 0x03000000, 0x0fe00000, "tst%p%c\t%16-19r, %o"},
{ARM_EXT_V1, 0x01000000, 0x0fe00010, "tst%p%c\t%16-19r, %o"},
{ARM_EXT_V1, 0x01200010, 0x0fe00090, "teq%p%c\t%16-19R, %o"},
{ARM_EXT_V1, 0x03400000, 0x0fe00000, "cmp%p%c\t%16-19r, %o"},
- {ARM_EXT_V3, 0x01400000, 0x0ff00010, "mrs%c\t%12-15R, %22?SCPSR"},
{ARM_EXT_V1, 0x01400000, 0x0fe00010, "cmp%p%c\t%16-19r, %o"},
{ARM_EXT_V1, 0x01400010, 0x0fe00090, "cmp%p%c\t%16-19R, %o"},
%x print warning if conditional an not at end of IT block"
%X print "\t; unpredictable <IT:code>" if conditional
%I print IT instruction suffix and operands
+ %W print Thumb Writeback indicator for LDMIA
%<bitfield>r print bitfield as an ARM register
%<bitfield>d print bitfield as a decimal
%<bitfield>H print (bitfield * 2) as a decimal
{ARM_EXT_V4T, 0x5000, 0xFA00, "str%10'b%c\t%0-2r, [%3-5r, %6-8r]"},
{ARM_EXT_V4T, 0x5800, 0xFA00, "ldr%10'b%c\t%0-2r, [%3-5r, %6-8r]"},
/* format 1 */
+ {ARM_EXT_V4T, 0x0000, 0xFFC0, "mov%C\t%0-2r, %3-5r"},
{ARM_EXT_V4T, 0x0000, 0xF800, "lsl%C\t%0-2r, %3-5r, #%6-10d"},
{ARM_EXT_V4T, 0x0800, 0xF800, "lsr%C\t%0-2r, %3-5r, %s"},
{ARM_EXT_V4T, 0x1000, 0xF800, "asr%C\t%0-2r, %3-5r, %s"},
{ARM_EXT_V4T, 0xA800, 0xF800, "add%c\t%8-10r, sp, #%0-7W"},
/* format 15 */
{ARM_EXT_V4T, 0xC000, 0xF800, "stmia%c\t%8-10r!, %M"},
- {ARM_EXT_V4T, 0xC800, 0xF800, "ldmia%c\t%8-10r!, %M"},
+ {ARM_EXT_V4T, 0xC800, 0xF800, "ldmia%c\t%8-10r%W, %M"},
/* format 17 */
{ARM_EXT_V4T, 0xDF00, 0xFF00, "svc%c\t%0-7d"},
/* format 16 */
%M print a modified 12-bit immediate (same location)
%J print a 16-bit immediate from hw1[3:0,10],hw2[14:12,7:0]
%K print a 16-bit immediate from hw2[3:0],hw1[3:0],hw2[11:4]
+ %H print a 16-bit immediate from hw2[3:0],hw1[11:0]
%S print a possibly-shifted Rm
%a print the address of a plain load/store
{ARM_EXT_DIV, 0xfb90f0f0, 0xfff0f0f0, "sdiv%c\t%8-11r, %16-19r, %0-3r"},
{ARM_EXT_DIV, 0xfbb0f0f0, 0xfff0f0f0, "udiv%c\t%8-11r, %16-19r, %0-3r"},
+ /* Virtualization Extension instructions. */
+ {ARM_EXT_VIRT, 0xf7e08000, 0xfff0f000, "hvc%c\t%V"},
+ /* We skip ERET as that is SUBS pc, lr, #0. */
+
+ /* MP Extension instructions. */
+ {ARM_EXT_MP, 0xf830f000, 0xff70f000, "pldw%c\t%a"},
+
+ /* Security extension instructions. */
+ {ARM_EXT_SEC, 0xf7f08000, 0xfff0f000, "smc%c\t%K"},
+
/* Instructions defined in the basic V6T2 set. */
{ARM_EXT_V6T2, 0xf3af8000, 0xffffffff, "nop%c.w"},
{ARM_EXT_V6T2, 0xf3af8001, 0xffffffff, "yield%c.w"},
{ARM_EXT_V6T2, 0xf3c08f00, 0xfff0ffff, "bxj%c\t%16-19r%x"},
{ARM_EXT_V6T2, 0xe810c000, 0xffd0ffff, "rfedb%c\t%16-19r%21'!"},
{ARM_EXT_V6T2, 0xe990c000, 0xffd0ffff, "rfeia%c\t%16-19r%21'!"},
- {ARM_EXT_V6T2, 0xf3ef8000, 0xffeff000, "mrs%c\t%8-11r, %D"},
+ {ARM_EXT_V6T2, 0xf3e08000, 0xffe0f000, "mrs%c\t%8-11r, %D"},
{ARM_EXT_V6T2, 0xf3af8100, 0xffffffe0, "cps\t#%0-4d%X"},
{ARM_EXT_V6T2, 0xe8d0f000, 0xfff0fff0, "tbb%c\t[%16-19r, %0-3r]%x"},
{ARM_EXT_V6T2, 0xe8d0f010, 0xfff0fff0, "tbh%c\t[%16-19r, %0-3r, lsl #1]%x"},
{ARM_EXT_V6T2, 0xfa90f090, 0xfff0f0f0, "rev16%c.w\t%8-11r, %16-19r"},
{ARM_EXT_V6T2, 0xfa90f0a0, 0xfff0f0f0, "rbit%c\t%8-11r, %16-19r"},
{ARM_EXT_V6T2, 0xfa90f0b0, 0xfff0f0f0, "revsh%c.w\t%8-11r, %16-19r"},
- {ARM_EXT_V6T2, 0xfaa0f000, 0xfff0f0f0, "saddsubx%c\t%8-11r, %16-19r, %0-3r"},
- {ARM_EXT_V6T2, 0xfaa0f010, 0xfff0f0f0, "qaddsubx%c\t%8-11r, %16-19r, %0-3r"},
- {ARM_EXT_V6T2, 0xfaa0f020, 0xfff0f0f0, "shaddsubx%c\t%8-11r, %16-19r, %0-3r"},
- {ARM_EXT_V6T2, 0xfaa0f040, 0xfff0f0f0, "uaddsubx%c\t%8-11r, %16-19r, %0-3r"},
- {ARM_EXT_V6T2, 0xfaa0f050, 0xfff0f0f0, "uqaddsubx%c\t%8-11r, %16-19r, %0-3r"},
- {ARM_EXT_V6T2, 0xfaa0f060, 0xfff0f0f0, "uhaddsubx%c\t%8-11r, %16-19r, %0-3r"},
+ {ARM_EXT_V6T2, 0xfaa0f000, 0xfff0f0f0, "sasx%c\t%8-11r, %16-19r, %0-3r"},
+ {ARM_EXT_V6T2, 0xfaa0f010, 0xfff0f0f0, "qasx%c\t%8-11r, %16-19r, %0-3r"},
+ {ARM_EXT_V6T2, 0xfaa0f020, 0xfff0f0f0, "shasx%c\t%8-11r, %16-19r, %0-3r"},
+ {ARM_EXT_V6T2, 0xfaa0f040, 0xfff0f0f0, "uasx%c\t%8-11r, %16-19r, %0-3r"},
+ {ARM_EXT_V6T2, 0xfaa0f050, 0xfff0f0f0, "uqasx%c\t%8-11r, %16-19r, %0-3r"},
+ {ARM_EXT_V6T2, 0xfaa0f060, 0xfff0f0f0, "uhasx%c\t%8-11r, %16-19r, %0-3r"},
{ARM_EXT_V6T2, 0xfaa0f080, 0xfff0f0f0, "sel%c\t%8-11r, %16-19r, %0-3r"},
{ARM_EXT_V6T2, 0xfab0f080, 0xfff0f0f0, "clz%c\t%8-11r, %16-19r"},
{ARM_EXT_V6T2, 0xfac0f000, 0xfff0f0f0, "ssub8%c\t%8-11r, %16-19r, %0-3r"},
{ARM_EXT_V6T2, 0xfad0f040, 0xfff0f0f0, "usub16%c\t%8-11r, %16-19r, %0-3r"},
{ARM_EXT_V6T2, 0xfad0f050, 0xfff0f0f0, "uqsub16%c\t%8-11r, %16-19r, %0-3r"},
{ARM_EXT_V6T2, 0xfad0f060, 0xfff0f0f0, "uhsub16%c\t%8-11r, %16-19r, %0-3r"},
- {ARM_EXT_V6T2, 0xfae0f000, 0xfff0f0f0, "ssubaddx%c\t%8-11r, %16-19r, %0-3r"},
- {ARM_EXT_V6T2, 0xfae0f010, 0xfff0f0f0, "qsubaddx%c\t%8-11r, %16-19r, %0-3r"},
- {ARM_EXT_V6T2, 0xfae0f020, 0xfff0f0f0, "shsubaddx%c\t%8-11r, %16-19r, %0-3r"},
- {ARM_EXT_V6T2, 0xfae0f040, 0xfff0f0f0, "usubaddx%c\t%8-11r, %16-19r, %0-3r"},
- {ARM_EXT_V6T2, 0xfae0f050, 0xfff0f0f0, "uqsubaddx%c\t%8-11r, %16-19r, %0-3r"},
- {ARM_EXT_V6T2, 0xfae0f060, 0xfff0f0f0, "uhsubaddx%c\t%8-11r, %16-19r, %0-3r"},
+ {ARM_EXT_V6T2, 0xfae0f000, 0xfff0f0f0, "ssax%c\t%8-11r, %16-19r, %0-3r"},
+ {ARM_EXT_V6T2, 0xfae0f010, 0xfff0f0f0, "qsax%c\t%8-11r, %16-19r, %0-3r"},
+ {ARM_EXT_V6T2, 0xfae0f020, 0xfff0f0f0, "shsax%c\t%8-11r, %16-19r, %0-3r"},
+ {ARM_EXT_V6T2, 0xfae0f040, 0xfff0f0f0, "usax%c\t%8-11r, %16-19r, %0-3r"},
+ {ARM_EXT_V6T2, 0xfae0f050, 0xfff0f0f0, "uqsax%c\t%8-11r, %16-19r, %0-3r"},
+ {ARM_EXT_V6T2, 0xfae0f060, 0xfff0f0f0, "uhsax%c\t%8-11r, %16-19r, %0-3r"},
{ARM_EXT_V6T2, 0xfb00f000, 0xfff0f0f0, "mul%c.w\t%8-11r, %16-19r, %0-3r"},
{ARM_EXT_V6T2, 0xfb70f000, 0xfff0f0f0, "usad8%c\t%8-11r, %16-19r, %0-3r"},
{ARM_EXT_V6T2, 0xfa00f000, 0xffe0f0f0, "lsl%20's%c.w\t%8-11R, %16-19R, %0-3R"},
{ARM_EXT_V6T2, 0xfbe00000, 0xfff000f0, "umlal%c\t%12-15R, %8-11R, %16-19R, %0-3R"},
{ARM_EXT_V6T2, 0xfbe00060, 0xfff000f0, "umaal%c\t%12-15R, %8-11R, %16-19R, %0-3R"},
{ARM_EXT_V6T2, 0xe8500f00, 0xfff00f00, "ldrex%c\t%12-15r, [%16-19r, #%0-7W]"},
- {ARM_EXT_V6T2, 0xf7f08000, 0xfff0f000, "smc%c\t%K"},
{ARM_EXT_V6T2, 0xf04f0000, 0xfbef8000, "mov%20's%c.w\t%8-11r, %M"},
{ARM_EXT_V6T2, 0xf06f0000, 0xfbef8000, "mvn%20's%c.w\t%8-11r, %M"},
{ARM_EXT_V6T2, 0xf810f000, 0xff70f000, "pld%c\t%a"},
{ARM_EXT_V6T2, 0xf0009000, 0xf800d000, "b%c.w\t%B%x"},
/* These have been 32-bit since the invention of Thumb. */
- {ARM_EXT_V4T, 0xf000c000, 0xf800d000, "blx%c\t%B%x"},
+ {ARM_EXT_V4T, 0xf000c000, 0xf800d001, "blx%c\t%B%x"},
{ARM_EXT_V4T, 0xf000d000, 0xf800d000, "bl%c\t%B%x"},
/* Fallback. */
fprintf_ftype func = info->fprintf_func;
unsigned long mask;
unsigned long value = 0;
- unsigned long allowed_arches = ((arm_feature_set *) info->private_data)->coproc;
+ struct arm_private_data *private_data = info->private_data;
+ unsigned long allowed_arches = private_data->features.coproc;
int cond;
for (insn = coprocessor_opcodes; insn->assembler; insn++)
continue;
case SENTINEL_GENERIC_START:
- allowed_arches = ((arm_feature_set *) info->private_data)->core;
+ allowed_arches = private_data->features.core;
continue;
default:
if (rn == 15 && (PRE_BIT_SET || WRITEBACK_BIT_SET))
{
func (stream, "\t; ");
- info->print_address_func (offset + pc
- + info->bytes_per_chunk * 2, info);
+ /* For unaligned PCs, apply off-by-alignment
+ correction. */
+ info->print_address_func (offset + pc
+ + info->bytes_per_chunk * 2
+ - (pc & 3),
+ info);
}
}
break;
func (stream, "d%d-d%d", rd, rd + n - 1);
func (stream, "}, [%s", arm_regnames[rn]);
if (align)
- func (stream, ", :%d", 32 << align);
+ func (stream, " :%d", 32 << align);
func (stream, "]");
if (rm == 0xd)
func (stream, "!");
rd + i * stride, idx);
func (stream, "}, [%s", arm_regnames[rn]);
if (align)
- func (stream, ", :%d", align);
+ func (stream, " :%d", align);
func (stream, "]");
if (rm == 0xd)
func (stream, "!");
if (type == 3)
align = (size > 1) ? align >> 1 : align;
if (type == 2 || (type == 0 && !size))
- func (stream, ", :<bad align %d>", align);
+ func (stream, " :<bad align %d>", align);
else
- func (stream, ", :%d", align);
+ func (stream, " :%d", align);
}
func (stream, "]");
if (rm == 0xd)
}
else
func (stream, "#%ld\t; 0x%.8lx",
- (long) (NEGATIVE_BIT_SET ? value | ~0xffffffffL : value),
+ (long) (((value & 0x80000000L) != 0)
+ ? value | ~0xffffffffL : value),
value);
break;
return FALSE;
}
+/* Return the name of a v7A special register. */
+
+static const char *
+banked_regname (unsigned reg)
+{
+ switch (reg)
+ {
+ case 15: return "CPSR";
+ case 32: return "R8_usr";
+ case 33: return "R9_usr";
+ case 34: return "R10_usr";
+ case 35: return "R11_usr";
+ case 36: return "R12_usr";
+ case 37: return "SP_usr";
+ case 38: return "LR_usr";
+ case 40: return "R8_fiq";
+ case 41: return "R9_fiq";
+ case 42: return "R10_fiq";
+ case 43: return "R11_fiq";
+ case 44: return "R12_fiq";
+ case 45: return "SP_fiq";
+ case 46: return "LR_fiq";
+ case 48: return "LR_irq";
+ case 49: return "SP_irq";
+ case 50: return "LR_svc";
+ case 51: return "SP_svc";
+ case 52: return "LR_abt";
+ case 53: return "SP_abt";
+ case 54: return "LR_und";
+ case 55: return "SP_und";
+ case 60: return "LR_mon";
+ case 61: return "SP_mon";
+ case 62: return "ELR_hyp";
+ case 63: return "SP_hyp";
+ case 79: return "SPSR";
+ case 110: return "SPSR_fiq";
+ case 112: return "SPSR_irq";
+ case 114: return "SPSR_svc";
+ case 116: return "SPSR_abt";
+ case 118: return "SPSR_und";
+ case 124: return "SPSR_mon";
+ case 126: return "SPSR_hyp";
+ default: return NULL;
+ }
+}
+
/* Print one ARM instruction from PC on INFO->STREAM. */
static void
const struct opcode32 *insn;
void *stream = info->stream;
fprintf_ftype func = info->fprintf_func;
+ struct arm_private_data *private_data = info->private_data;
if (print_insn_coprocessor (pc, info, given, FALSE))
return;
if ((given & insn->mask) != insn->value)
continue;
- if ((insn->arch & ((arm_feature_set *) info->private_data)->core) == 0)
+ if ((insn->arch & private_data->features.core) == 0)
continue;
/* Special case: an instruction with all bits set in the condition field
/* The p-variants of tst/cmp/cmn/teq are the pre-V6
mechanism for setting PSR flag bits. They are
obsolete in V6 onwards. */
- if (((((arm_feature_set *) info->private_data)->core) & ARM_EXT_V6) == 0)
+ if ((private_data->features.core & ARM_EXT_V6) == 0)
func (stream, "p");
}
break;
break;
case 'C':
- func (stream, "_");
- if (given & 0x80000)
- func (stream, "f");
- if (given & 0x40000)
- func (stream, "s");
- if (given & 0x20000)
- func (stream, "x");
- if (given & 0x10000)
- func (stream, "c");
+ if ((given & 0x02000200) == 0x200)
+ {
+ const char * name;
+ unsigned sysm = (given & 0x004f0000) >> 16;
+
+ sysm |= (given & 0x300) >> 4;
+ name = banked_regname (sysm);
+
+ if (name != NULL)
+ func (stream, "%s", name);
+ else
+ func (stream, "(UNDEF: %lu)", sysm);
+ }
+ else
+ {
+ func (stream, "%cPSR_",
+ (given & 0x00400000) ? 'S' : 'C');
+ if (given & 0x80000)
+ func (stream, "f");
+ if (given & 0x40000)
+ func (stream, "s");
+ if (given & 0x20000)
+ func (stream, "x");
+ if (given & 0x10000)
+ func (stream, "c");
+ }
break;
case 'U':
- switch (given & 0xf)
+ if ((given & 0xf0) == 0x60)
{
- case 0xf: func (stream, "sy"); break;
- case 0x7: func (stream, "un"); break;
- case 0xe: func (stream, "st"); break;
- case 0x6: func (stream, "unst"); break;
- default:
- func (stream, "#%d", (int) given & 0xf);
- break;
+ switch (given & 0xf)
+ {
+ case 0xf: func (stream, "sy"); break;
+ default:
+ func (stream, "#%d", (int) given & 0xf);
+ break;
+ }
+ }
+ else
+ {
+ switch (given & 0xf)
+ {
+ case 0xf: func (stream, "sy"); break;
+ case 0x7: func (stream, "un"); break;
+ case 0xe: func (stream, "st"); break;
+ case 0x6: func (stream, "unst"); break;
+ case 0xb: func (stream, "ish"); break;
+ case 0xa: func (stream, "ishst"); break;
+ case 0x3: func (stream, "osh"); break;
+ case 0x2: func (stream, "oshst"); break;
+ default:
+ func (stream, "#%d", (int) given & 0xf);
+ break;
+ }
}
break;
}
break;
+ case 'R':
+ /* Get the PSR/banked register name. */
+ {
+ const char * name;
+ unsigned sysm = (given & 0x004f0000) >> 16;
+
+ sysm |= (given & 0x300) >> 4;
+ name = banked_regname (sysm);
+
+ if (name != NULL)
+ func (stream, "%s", name);
+ else
+ func (stream, "(UNDEF: %lu)", sysm);
+ }
+ break;
+
case 'V':
/* 16-bit unsigned immediate from a MOVT or MOVW
instruction, encoded in bits 0:11 and 15:19. */
}
break;
+ case 'W':
+ /* Print writeback indicator for a LDMIA. We are doing a
+ writeback if the base register is not in the register
+ mask. */
+ if ((given & (1 << ((given & 0x0700) >> 8))) == 0)
+ func (stream, "!");
+ break;
+
case 'b':
/* Print ARM V6T2 CZB address: pc+4+6 bits. */
{
}
break;
+ case 'V':
+ {
+ unsigned int imm = 0;
+
+ imm |= (given & 0x00000fffu);
+ imm |= (given & 0x000f0000u) >> 4;
+ func (stream, "#%u", imm);
+ value_in_comment = imm;
+ }
+ break;
+
case 'S':
{
unsigned int reg = (given & 0x0000000fu);
break;
case 'U':
- switch (given & 0xf)
+ if ((given & 0xf0) == 0x60)
{
- case 0xf: func (stream, "sy"); break;
- case 0x7: func (stream, "un"); break;
- case 0xe: func (stream, "st"); break;
- case 0x6: func (stream, "unst"); break;
- default:
- func (stream, "#%d", (int) given & 0xf);
- break;
+ switch (given & 0xf)
+ {
+ case 0xf: func (stream, "sy"); break;
+ default:
+ func (stream, "#%d", (int) given & 0xf);
+ break;
+ }
}
+ else
+ {
+ switch (given & 0xf)
+ {
+ case 0xf: func (stream, "sy"); break;
+ case 0x7: func (stream, "un"); break;
+ case 0xe: func (stream, "st"); break;
+ case 0x6: func (stream, "unst"); break;
+ case 0xb: func (stream, "ish"); break;
+ case 0xa: func (stream, "ishst"); break;
+ case 0x3: func (stream, "osh"); break;
+ case 0x2: func (stream, "oshst"); break;
+ default:
+ func (stream, "#%d", (int) given & 0xf);
+ break;
+ }
+ }
break;
case 'C':
if (given & 0x100)
func (stream, "c");
}
+ else if ((given & 0x20) == 0x20)
+ {
+ char const* name;
+ unsigned sysm = (given & 0xf00) >> 8;
+
+ sysm |= (given & 0x30);
+ sysm |= (given & 0x00100000) >> 14;
+ name = banked_regname (sysm);
+
+ if (name != NULL)
+ func (stream, "%s", name);
+ else
+ func (stream, "(UNDEF: %lu)", sysm);
+ }
else
{
func (stream, psr_name (given & 0xff));
break;
case 'D':
- if ((given & 0xff) == 0)
- func (stream, "%cPSR", (given & 0x100000) ? 'S' : 'C');
+ if (((given & 0xff) == 0)
+ || ((given & 0x20) == 0x20))
+ {
+ char const* name;
+ unsigned sm = (given & 0xf0000) >> 16;
+
+ sm |= (given & 0x30);
+ sm |= (given & 0x00100000) >> 14;
+ name = banked_regname (sm);
+
+ if (name != NULL)
+ func (stream, "%s", name);
+ else
+ func (stream, "(UNDEF: %lu)", sm);
+ }
else
func (stream, psr_name (given & 0xff));
break;
ifthen_state = 0;
}
-/* Try to infer the code type (Arm or Thumb) from a symbol.
+/* Returns nonzero and sets *MAP_TYPE if the N'th symbol is a
+ mapping symbol. */
+
+static int
+is_mapping_symbol (struct disassemble_info *info, int n,
+ enum map_type *map_type)
+{
+ const char *name;
+
+ name = bfd_asymbol_name (info->symtab[n]);
+ if (name[0] == '$' && (name[1] == 'a' || name[1] == 't' || name[1] == 'd')
+ && (name[2] == 0 || name[2] == '.'))
+ {
+ *map_type = ((name[1] == 'a') ? MAP_ARM
+ : (name[1] == 't') ? MAP_THUMB
+ : MAP_DATA);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/* Try to infer the code type (ARM or Thumb) from a mapping symbol.
+ Returns nonzero if *MAP_TYPE was set. */
+
+static int
+get_map_sym_type (struct disassemble_info *info,
+ int n,
+ enum map_type *map_type)
+{
+ /* If the symbol is in a different section, ignore it. */
+ if (info->section != NULL && info->section != info->symtab[n]->section)
+ return FALSE;
+
+ return is_mapping_symbol (info, n, map_type);
+}
+
+/* Try to infer the code type (ARM or Thumb) from a non-mapping symbol.
Returns nonzero if *MAP_TYPE was set. */
static int
{
elf_symbol_type *es;
unsigned int type;
- const char *name;
+
+ /* If the symbol is in a different section, ignore it. */
+ if (info->section != NULL && info->section != info->symtab[n]->section)
+ return FALSE;
es = *(elf_symbol_type **)(info->symtab + n);
type = ELF_ST_TYPE (es->internal_elf_sym.st_info);
return TRUE;
}
- /* Check for mapping symbols. */
- name = bfd_asymbol_name (info->symtab[n]);
- if (name[0] == '$' && (name[1] == 'a' || name[1] == 't' || name[1] == 'd')
- && (name[2] == 0 || name[2] == '.'))
- {
- *map_type = ((name[1] == 'a') ? MAP_ARM
- : (name[1] == 't') ? MAP_THUMB
- : MAP_DATA);
- return TRUE;
- }
-
return FALSE;
}
long given;
int status;
int is_thumb = FALSE;
- int is_data = (bfd_asymbol_flavour (*info->symtab)
- == bfd_target_elf_flavour) ? TRUE : FALSE;
+ int is_data = FALSE;
int little_code;
unsigned int size = 4;
void (*printer) (bfd_vma, struct disassemble_info *, long);
bfd_boolean found = FALSE;
+ struct arm_private_data *private_data;
if (info->disassembler_options)
{
/* PR 10288: Control which instructions will be disassembled. */
if (info->private_data == NULL)
{
- static arm_feature_set features;
+ static struct arm_private_data private;
if ((info->flags & USER_SPECIFIED_MACHINE_TYPE) == 0)
/* If the user did not use the -m command line switch then default to
/* Compute the architecture bitmask from the machine number.
Note: This assumes that the machine number will not change
during disassembly.... */
- select_arm_features (info->mach, & features);
+ select_arm_features (info->mach, & private.features);
+
+ private.has_mapping_symbols = -1;
- info->private_data = & features;
+ info->private_data = & private;
}
-
+
+ private_data = info->private_data;
+
/* Decide if our code is going to be little-endian, despite what the
function argument might say. */
little_code = ((info->endian_code == BFD_ENDIAN_LITTLE) || little);
- /* First check the full symtab for a mapping symbol, even if there
- are no usable non-mapping symbols for this address. */
+ /* For ELF, consult the symbol table to determine what kind of code
+ or data we have. */
if (info->symtab_size != 0
&& bfd_asymbol_flavour (*info->symtab) == bfd_target_elf_flavour)
{
bfd_vma addr;
- int n;
+ int n, start;
int last_sym = -1;
- enum map_type type = MAP_DATA;
+ enum map_type type = MAP_ARM;
- if (pc <= last_mapping_addr)
- last_mapping_sym = -1;
- is_thumb = (last_type == MAP_THUMB);
- found = FALSE;
/* Start scanning at the start of the function, or wherever
we finished last time. */
- n = info->symtab_pos + 1;
- if (n < last_mapping_sym)
- n = last_mapping_sym;
+ start = info->symtab_pos + 1;
+ if (start < last_mapping_sym)
+ start = last_mapping_sym;
+ found = FALSE;
- /* Scan up to the location being disassembled. */
- for (; n < info->symtab_size; n++)
+ /* First, look for mapping symbols. */
+ if (private_data->has_mapping_symbols != 0)
{
- addr = bfd_asymbol_value (info->symtab[n]);
- if (addr > pc)
- break;
- if ((info->section == NULL
- || info->section == info->symtab[n]->section)
- && get_sym_code_type (info, n, &type))
+ /* Scan up to the location being disassembled. */
+ for (n = start; n < info->symtab_size; n++)
{
- last_sym = n;
+ addr = bfd_asymbol_value (info->symtab[n]);
+ if (addr > pc)
+ break;
+ if (get_map_sym_type (info, n, &type))
+ {
+ last_sym = n;
+ found = TRUE;
+ }
+ }
+
+ if (!found)
+ {
+ /* No mapping symbol found at this address. Look backwards
+ for a preceeding one. */
+ for (n = start - 1; n >= 0; n--)
+ {
+ if (get_map_sym_type (info, n, &type))
+ {
+ last_sym = n;
+ found = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (found)
+ private_data->has_mapping_symbols = 1;
+
+ /* No mapping symbols were found. A leading $d may be
+ omitted for sections which start with data; but for
+ compatibility with legacy and stripped binaries, only
+ assume the leading $d if there is at least one mapping
+ symbol in the file. */
+ if (!found && private_data->has_mapping_symbols == -1)
+ {
+ /* Look for mapping symbols, in any section. */
+ for (n = 0; n < info->symtab_size; n++)
+ if (is_mapping_symbol (info, n, &type))
+ {
+ private_data->has_mapping_symbols = 1;
+ break;
+ }
+ if (private_data->has_mapping_symbols == -1)
+ private_data->has_mapping_symbols = 0;
+ }
+
+ if (!found && private_data->has_mapping_symbols == 1)
+ {
+ type = MAP_DATA;
found = TRUE;
}
}
+ /* Next search for function symbols to separate ARM from Thumb
+ in binaries without mapping symbols. */
if (!found)
{
- n = info->symtab_pos;
- if (n < last_mapping_sym - 1)
- n = last_mapping_sym - 1;
-
- /* No mapping symbol found at this address. Look backwards
- for a preceeding one. */
- for (; n >= 0; n--)
+ /* Scan up to the location being disassembled. */
+ for (n = start; n < info->symtab_size; n++)
{
- if ((info->section == NULL
- || info->section == info->symtab[n]->section)
- && get_sym_code_type (info, n, &type))
+ addr = bfd_asymbol_value (info->symtab[n]);
+ if (addr > pc)
+ break;
+ if (get_sym_code_type (info, n, &type))
{
last_sym = n;
found = TRUE;
- break;
+ }
+ }
+
+ if (!found)
+ {
+ /* No mapping symbol found at this address. Look backwards
+ for a preceeding one. */
+ for (n = start - 1; n >= 0; n--)
+ {
+ if (get_sym_code_type (info, n, &type))
+ {
+ last_sym = n;
+ found = TRUE;
+ break;
+ }
}
}
}