Add ATPCS support to ARM disassembler.

Document ARM disassembler options.
This commit is contained in:
Nick Clifton
2000-01-27 22:17:12 +00:00
parent 94470b237b
commit 58efb6c0fd
7 changed files with 216 additions and 173 deletions

View File

@ -1,5 +1,8 @@
2000-01-27 Nick Clifton <nickc@redhat.com> 2000-01-27 Nick Clifton <nickc@redhat.com>
* binutils.texi (objdump): Document new ARM specific
disassembler options.
* objdump.c (usage): Call disassembler_usage(). * objdump.c (usage): Call disassembler_usage().
2000-01-27 Alan Modra <alan@spri.levels.unisa.edu.au> 2000-01-27 Alan Modra <alan@spri.levels.unisa.edu.au>

View File

@ -1346,13 +1346,17 @@ some targets.
If the target is an ARM architecture then this switch can be used to If the target is an ARM architecture then this switch can be used to
select which register name set is used during disassembler. Specifying select which register name set is used during disassembler. Specifying
@samp{--disassembler-options=reg-name-std} (the default) will select the @samp{-M reg-name-std} (the default) will select the register names as
register names as used in ARM's instruction set documentation, but with used in ARM's instruction set documentation, but with register 13 called
register 13 called 'sp', register 14 called 'lr' and register 15 called 'sp', register 14 called 'lr' and register 15 called 'pc'. Specifying
'pc'. Specifying @samp{--disassembler-options=reg-names-apcs} will @samp{-M reg-names-apcs} will select the name set used by the ARM
select the name set used by the ARM Procedure Call Standard, whilst Procedure Call Standard, whilst specifying @samp{-M reg-names-raw} will
specifying @samp{--disassembler-options=reg-names-raw} will just use just use @samp{r} followed by the register number.
@samp{r} followed by the register number.
There are also two variants on the APCS register naming scheme enabled
by @samp{-M reg-names-atpcs} and @samp{-M reg-names-atpcs-special} which
use the ARM/Thumb Procedure Call Standard naming conventions. (Eiuther
with the normal register name sor the special register names).
This option can also be used for ARM architectures to force the This option can also be used for ARM architectures to force the
disassembler to interpret all instructions as THUMB instructions by disassembler to interpret all instructions as THUMB instructions by

View File

@ -1,6 +1,8 @@
2000-01-27 Nick Clifton <nickc@redhat.com> 2000-01-27 Nick Clifton <nickc@redhat.com>
* dis-asm.h: Add prototype for disassembler_usage(). * dis-asm.h: Add prototype for disassembler_usage().
Add prototype for arm_disassembler_options().
Remvoe prototype for arm_toggle_regnames().
1999-12-15 Doug Evans <dje@transmeta.com> 1999-12-15 Doug Evans <dje@transmeta.com>

View File

@ -189,7 +189,7 @@ extern int print_insn_vax PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_tic80 PARAMS ((bfd_vma, disassemble_info*)); extern int print_insn_tic80 PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_pj PARAMS ((bfd_vma, disassemble_info*)); extern int print_insn_pj PARAMS ((bfd_vma, disassemble_info*));
extern int arm_toggle_regnames PARAMS ((void)); extern void print_arm_disassembler_options PARAMS ((FILE *));
/* Fetch the disassembler for a given BFD, if that support is available. */ /* Fetch the disassembler for a given BFD, if that support is available. */
extern disassembler_ftype disassembler PARAMS ((bfd *)); extern disassembler_ftype disassembler PARAMS ((bfd *));

View File

@ -2,7 +2,21 @@
* disassemble.c (disassembler_usage): New function: Print out any * disassemble.c (disassembler_usage): New function: Print out any
target specific disassembler options. target specific disassembler options.
Call arm_disassembler_options() if the ARM architecture is being
supported.
* arm-dis.c (NUM_ELEM): Define this macro if not already
defined.
(arm_regname): New struct type for ARM register names.
(arm_toggle_regnames): Delete.
(parse_disassembler_option): Use register name structure.
(print_insn): New function: Combines duplicate code found in
print_insn_big_arm and print_insn_little_arm.
(print_insn_big_arm): Call print_insn.
(print_insn_little_arm): Call print_insn.
(print_arm_disassembler_options): Display list of supported,
ARM specific disassembler options.
2000-01-27 Thomas de Lellis <tdel@windriver.com> 2000-01-27 Thomas de Lellis <tdel@windriver.com>
* arm-dis.c (printf_insn_big_arm): Treat ELF symbols with the * arm-dis.c (printf_insn_big_arm): Treat ELF symbols with the

View File

@ -33,30 +33,48 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "elf/arm.h" #include "elf/arm.h"
#ifndef streq #ifndef streq
#define streq(a,b) (strcmp ((a), (b)) == 0) #define streq(a,b) (strcmp ((a), (b)) == 0)
#endif #endif
#ifndef strneq #ifndef strneq
#define strneq(a,b,n) (strncmp ((a), (b), (n)) == 0) #define strneq(a,b,n) (strncmp ((a), (b), (n)) == 0)
#endif
#ifndef NUM_ELEM
#define NUM_ELEM(a) (sizeof (a) / sizeof (a)[0])
#endif #endif
static char * arm_conditional[] = static char * arm_conditional[] =
{"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", {"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
"hi", "ls", "ge", "lt", "gt", "le", "", "nv"}; "hi", "ls", "ge", "lt", "gt", "le", "", "nv"};
static char * arm_regnames_raw[] = typedef struct
{"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", {
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}; const char * name;
const char * description;
const char * reg_names[16];
}
arm_regname;
static char * arm_regnames_standard[] = static arm_regname regnames[] =
{"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", {
"r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc"}; { "raw" , "Select raw register names",
{ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}},
{ "std", "Select register names used in ARM's ISA documentation",
{ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc" }},
{ "apcs", "Select register names used in the APCS",
{ "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "sl", "fp", "ip", "sp", "lr", "pc" }},
{ "atpcs", "Select register names used in the ATPCS",
{ "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "IP", "SP", "LR", "PC" }},
{ "atpcs-special", "Select special register names used in the ATPCS",
{ "a1", "a2", "a3", "a4", "v1", "v2", "v3", "WR", "v5", "SB", "SL", "FP", "IP", "SP", "LR", "PC" }}
};
static char * arm_regnames_apcs[] = /* Default to standard register name set. */
{"a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", static unsigned int regname_selected = 1;
"v5", "v6", "sl", "fp", "ip", "sp", "lr", "pc"};
/* Choose which register name set to use. */ #define NUM_ARM_REGNAMES NUM_ELEM (regnames)
static char ** arm_regnames = arm_regnames_standard; #define arm_regnames regnames[regname_selected].reg_names
static boolean force_thumb = false; static boolean force_thumb = false;
@ -72,6 +90,7 @@ static int print_insn_arm PARAMS ((bfd_vma, struct disassemble_info *, long))
static int print_insn_thumb PARAMS ((bfd_vma, struct disassemble_info *, long)); static int print_insn_thumb PARAMS ((bfd_vma, struct disassemble_info *, long));
static void parse_disassembler_option PARAMS ((char *)); static void parse_disassembler_option PARAMS ((char *));
static void parse_disassembler_options PARAMS ((char *)); static void parse_disassembler_options PARAMS ((char *));
static int print_insn PARAMS ((bfd_vma, struct disassemble_info *, boolean));
/* Functions. */ /* Functions. */
static void static void
@ -110,7 +129,6 @@ arm_decode_shift (given, func, stream)
/* Print one instruction from PC on INFO->STREAM. /* Print one instruction from PC on INFO->STREAM.
Return the size of the instruction (always 4 on ARM). */ Return the size of the instruction (always 4 on ARM). */
static int static int
print_insn_arm (pc, info, given) print_insn_arm (pc, info, given)
bfd_vma pc; bfd_vma pc;
@ -155,18 +173,19 @@ print_insn_arm (pc, info, given)
offset += pc + 8; offset += pc + 8;
/* Cope with the possibility of write-back being used. /* Cope with the possibility of write-back
Probably a very dangerous thing for the programmer being used. Probably a very dangerous thing
to do, but who are we to argue ? */ for the programmer to do, but who are we to
argue ? */
if (given & 0x00200000) if (given & 0x00200000)
func (stream, "!"); func (stream, "!");
} }
else else
{ {
/* post indexed */ /* Post indexed. */
func (stream, "], #%x", offset); func (stream, "], #%x", offset);
offset = pc + 8; /* ie ignore the offset */ offset = pc + 8; /* ie ignore the offset. */
} }
func (stream, "\t; "); func (stream, "\t; ");
@ -223,7 +242,7 @@ print_insn_arm (pc, info, given)
case 's': case 's':
if ((given & 0x004f0000) == 0x004f0000) if ((given & 0x004f0000) == 0x004f0000)
{ {
/* PC relative with immediate offset */ /* PC relative with immediate offset. */
int offset = ((given & 0xf00) >> 4) | (given & 0xf); int offset = ((given & 0xf00) >> 4) | (given & 0xf);
if ((given & 0x00800000) == 0) if ((given & 0x00800000) == 0)
@ -240,10 +259,10 @@ print_insn_arm (pc, info, given)
arm_regnames[(given >> 16) & 0xf]); arm_regnames[(given >> 16) & 0xf]);
if ((given & 0x01000000) != 0) if ((given & 0x01000000) != 0)
{ {
/* pre-indexed */ /* Pre-indexed. */
if ((given & 0x00400000) == 0x00400000) if ((given & 0x00400000) == 0x00400000)
{ {
/* immediate */ /* Immediate. */
int offset = ((given & 0xf00) >> 4) | (given & 0xf); int offset = ((given & 0xf00) >> 4) | (given & 0xf);
if (offset) if (offset)
func (stream, ", %s#%d", func (stream, ", %s#%d",
@ -252,7 +271,7 @@ print_insn_arm (pc, info, given)
} }
else else
{ {
/* register */ /* Register. */
func (stream, ", %s%s", func (stream, ", %s%s",
(((given & 0x00800000) == 0) (((given & 0x00800000) == 0)
? "-" : ""), ? "-" : ""),
@ -264,10 +283,10 @@ print_insn_arm (pc, info, given)
} }
else else
{ {
/* post-indexed */ /* Post-indexed. */
if ((given & 0x00400000) == 0x00400000) if ((given & 0x00400000) == 0x00400000)
{ {
/* immediate */ /* Immediate. */
int offset = ((given & 0xf00) >> 4) | (given & 0xf); int offset = ((given & 0xf00) >> 4) | (given & 0xf);
if (offset) if (offset)
func (stream, "], %s#%d", func (stream, "], %s#%d",
@ -278,7 +297,7 @@ print_insn_arm (pc, info, given)
} }
else else
{ {
/* register */ /* Register. */
func (stream, "], %s%s", func (stream, "], %s%s",
(((given & 0x00800000) == 0) (((given & 0x00800000) == 0)
? "-" : ""), ? "-" : ""),
@ -469,36 +488,46 @@ print_insn_arm (pc, info, given)
{ {
case '-': case '-':
c++; c++;
while (*c >= '0' && *c <= '9') while (*c >= '0' && *c <= '9')
bitend = (bitend * 10) + *c++ - '0'; bitend = (bitend * 10) + *c++ - '0';
if (!bitend) if (!bitend)
abort (); abort ();
switch (*c) switch (*c)
{ {
case 'r': case 'r':
{ {
long reg; long reg;
reg = given >> bitstart; reg = given >> bitstart;
reg &= (2 << (bitend - bitstart)) - 1; reg &= (2 << (bitend - bitstart)) - 1;
func (stream, "%s", arm_regnames[reg]); func (stream, "%s", arm_regnames[reg]);
} }
break; break;
case 'd': case 'd':
{ {
long reg; long reg;
reg = given >> bitstart; reg = given >> bitstart;
reg &= (2 << (bitend - bitstart)) - 1; reg &= (2 << (bitend - bitstart)) - 1;
func (stream, "%d", reg); func (stream, "%d", reg);
} }
break; break;
case 'x': case 'x':
{ {
long reg; long reg;
reg = given >> bitstart; reg = given >> bitstart;
reg &= (2 << (bitend - bitstart)) - 1; reg &= (2 << (bitend - bitstart)) - 1;
func (stream, "0x%08x", reg); func (stream, "0x%08x", reg);
/* Some SWI instructions have special meanings. */ /* Some SWI instructions have special
meanings. */
if ((given & 0x0fffffff) == 0x0FF00000) if ((given & 0x0fffffff) == 0x0FF00000)
func (stream, "\t; IMB"); func (stream, "\t; IMB");
else if ((given & 0x0fffffff) == 0x0FF00001) else if ((given & 0x0fffffff) == 0x0FF00001)
@ -508,16 +537,20 @@ print_insn_arm (pc, info, given)
case 'X': case 'X':
{ {
long reg; long reg;
reg = given >> bitstart; reg = given >> bitstart;
reg &= (2 << (bitend - bitstart)) - 1; reg &= (2 << (bitend - bitstart)) - 1;
func (stream, "%01x", reg & 0xf); func (stream, "%01x", reg & 0xf);
} }
break; break;
case 'f': case 'f':
{ {
long reg; long reg;
reg = given >> bitstart; reg = given >> bitstart;
reg &= (2 << (bitend - bitstart)) - 1; reg &= (2 << (bitend - bitstart)) - 1;
if (reg > 7) if (reg > 7)
func (stream, "#%s", func (stream, "#%s",
arm_fp_const[reg & 7]); arm_fp_const[reg & 7]);
@ -529,6 +562,7 @@ print_insn_arm (pc, info, given)
abort (); abort ();
} }
break; break;
case '`': case '`':
c++; c++;
if ((given & (1 << bitstart)) == 0) if ((given & (1 << bitstart)) == 0)
@ -567,7 +601,6 @@ print_insn_arm (pc, info, given)
/* Print one instruction from PC on INFO->STREAM. /* Print one instruction from PC on INFO->STREAM.
Return the size of the instruction. */ Return the size of the instruction. */
static int static int
print_insn_thumb (pc, info, given) print_insn_thumb (pc, info, given)
bfd_vma pc; bfd_vma pc;
@ -584,15 +617,14 @@ print_insn_thumb (pc, info, given)
{ {
char * c = insn->assembler; char * c = insn->assembler;
/* Special processing for Thumb 2 instruction BL sequence: */ /* Special processing for Thumb 2 instruction BL sequence: */
if (!*c) /* check for empty (not NULL) assembler string */ if (!*c) /* Check for empty (not NULL) assembler string. */
{ {
info->bytes_per_chunk = 4; info->bytes_per_chunk = 4;
info->bytes_per_line = 4; info->bytes_per_line = 4;
func (stream, "bl\t"); func (stream, "bl\t");
(*info->print_address_func) info->print_address_func (BDISP23 (given) * 2 + pc + 4, info);
(BDISP23 (given) * 2 + pc + 4, info);
return 4; return 4;
} }
else else
@ -601,7 +633,7 @@ print_insn_thumb (pc, info, given)
info->bytes_per_line = 4; info->bytes_per_line = 4;
given &= 0xffff; given &= 0xffff;
for (; *c; c++) for (; *c; c++)
{ {
if (*c == '%') if (*c == '%')
@ -618,9 +650,11 @@ print_insn_thumb (pc, info, given)
case 'S': case 'S':
{ {
long reg; long reg;
reg = (given >> 3) & 0x7; reg = (given >> 3) & 0x7;
if (given & (1 << 6)) if (given & (1 << 6))
reg += 8; reg += 8;
func (stream, "%s", arm_regnames[reg]); func (stream, "%s", arm_regnames[reg]);
} }
break; break;
@ -632,6 +666,7 @@ print_insn_thumb (pc, info, given)
reg = given & 0x7; reg = given & 0x7;
if (given & (1 << 7)) if (given & (1 << 7))
reg += 8; reg += 8;
func (stream, "%s", arm_regnames[reg]); func (stream, "%s", arm_regnames[reg]);
} }
break; break;
@ -644,17 +679,18 @@ print_insn_thumb (pc, info, given)
case 'N': case 'N':
if (given & (1 << 8)) if (given & (1 << 8))
domasklr = 1; domasklr = 1;
/* fall through */ /* Fall through. */
case 'O': case 'O':
if (*c == 'O' && (given & (1 << 8))) if (*c == 'O' && (given & (1 << 8)))
domaskpc = 1; domaskpc = 1;
/* fall through */ /* Fall through. */
case 'M': case 'M':
{ {
int started = 0; int started = 0;
int reg; int reg;
func (stream, "{"); func (stream, "{");
/* It would be nice if we could spot /* It would be nice if we could spot
ranges, and generate the rS-rE format: */ ranges, and generate the rS-rE format: */
for (reg = 0; (reg < 8); reg++) for (reg = 0; (reg < 8); reg++)
@ -728,8 +764,8 @@ print_insn_thumb (pc, info, given)
case 'a': case 'a':
/* PC-relative address -- the bottom two /* PC-relative address -- the bottom two
bits of the address are dropped before bits of the address are dropped
the calculation. */ before the calculation. */
info->print_address_func info->print_address_func
(((pc + 4) & ~3) + (reg << 2), info); (((pc + 4) & ~3) + (reg << 2), info);
break; break;
@ -787,23 +823,11 @@ print_insn_thumb (pc, info, given)
} }
} }
/* no match */ /* No match. */
abort (); abort ();
} }
/* Select a different register name set. /* Parse an individual disassembler option. */
Returns true if the name set selected is the APCS name set. */
int
arm_toggle_regnames ()
{
if (arm_regnames == arm_regnames_standard)
arm_regnames = arm_regnames_apcs;
else
arm_regnames = arm_regnames_standard;
return arm_regnames == arm_regnames_apcs;
}
static void static void
parse_disassembler_option (option) parse_disassembler_option (option)
char * option; char * option;
@ -813,27 +837,31 @@ parse_disassembler_option (option)
if (strneq (option, "reg-names-", 10)) if (strneq (option, "reg-names-", 10))
{ {
int i;
option += 10; option += 10;
for (i = NUM_ARM_REGNAMES; i--;)
if (streq (option, regnames[i].name))
{
regname_selected = i;
break;
}
if (streq (option, "std")) if (i < 0)
arm_regnames = arm_regnames_standard; fprintf (stderr, _("Unrecognised register name set: %s\n"), option);
else if (streq (option, "apcs"))
arm_regnames = arm_regnames_apcs;
else if (streq (option, "raw"))
arm_regnames = arm_regnames_raw;
else
fprintf (stderr, "Unrecognised register name set: %s\n", option);
} }
else if (streq (option, "force-thumb")) else if (streq (option, "force-thumb"))
force_thumb = 1; force_thumb = 1;
else if (streq (option, "no-force-thumb")) else if (streq (option, "no-force-thumb"))
force_thumb = 0; force_thumb = 0;
else else
fprintf (stderr, "Unrecognised disassembler option: %s\n", option); fprintf (stderr, _("Unrecognised disassembler option: %s\n"), option);
return; return;
} }
/* Parse the string of disassembler options, spliting it at whitespaces. */
static void static void
parse_disassembler_options (options) parse_disassembler_options (options)
char * options; char * options;
@ -860,24 +888,24 @@ parse_disassembler_options (options)
while (space); while (space);
} }
/* NOTE: There are no checks in these routines that the relevant number of /* NOTE: There are no checks in these routines that
data bytes exist. */ the relevant number of data bytes exist. */
static int
int print_insn (pc, info, little)
print_insn_big_arm (pc, info)
bfd_vma pc; bfd_vma pc;
struct disassemble_info * info; struct disassemble_info * info;
boolean little;
{ {
unsigned char b[4]; unsigned char b[4];
long given; long given;
int status; int status;
int is_thumb; int is_thumb;
if (info->disassembler_options) if (info->disassembler_options)
{ {
parse_disassembler_options (info->disassembler_options); parse_disassembler_options (info->disassembler_options);
/* To avoid repeated parsing of the options, we remove it here. */ /* To avoid repeated parsing of these options, we remove them here. */
info->disassembler_options = NULL; info->disassembler_options = NULL;
} }
@ -899,46 +927,70 @@ print_insn_big_arm (pc, info)
else if (bfd_asymbol_flavour (*info->symbols) == bfd_target_elf_flavour) else if (bfd_asymbol_flavour (*info->symbols) == bfd_target_elf_flavour)
{ {
elf_symbol_type * es; elf_symbol_type * es;
unsigned int type;
es = *(elf_symbol_type **)(info->symbols); es = *(elf_symbol_type **)(info->symbols);
is_thumb = (ELF_ST_TYPE (es->internal_elf_sym.st_info) == STT_ARM_TFUNC) type = ELF_ST_TYPE (es->internal_elf_sym.st_info);
|| (ELF_ST_TYPE (es->internal_elf_sym.st_info) == STT_ARM_16BIT);
}
}
info->bytes_per_chunk = 4;
info->display_endian = BFD_ENDIAN_BIG;
/* Always fetch word aligned values. */
status = (*info->read_memory_func) (pc & ~ 0x3, (bfd_byte *) &b[0], 4, info);
if (status != 0)
{
(*info->memory_error_func) (status, pc, info);
return -1;
}
if (is_thumb)
{
if (pc & 0x2)
{
given = (b[2] << 8) | b[3];
status = info->read_memory_func ((pc + 4) & ~ 0x3, (bfd_byte *) b, 4, info);
if (status != 0)
{
info->memory_error_func (status, pc + 4, info);
return -1;
}
given |= (b[0] << 24) | (b[1] << 16); is_thumb = (type == STT_ARM_TFUNC) || (type == STT_ARM_16BIT);
} }
else }
given = (b[0] << 8) | b[1] | (b[2] << 24) | (b[3] << 16);
info->bytes_per_chunk = 4;
info->display_endian = little ? BFD_ENDIAN_LITTLE : BFD_ENDIAN_BIG;
if (little)
{
status = info->read_memory_func (pc, (bfd_byte *) &b[0], 4, info);
if (status != 0 && is_thumb)
{
info->bytes_per_chunk = 2;
status = info->read_memory_func (pc, (bfd_byte *) b, 2, info);
b[3] = b[2] = 0;
}
if (status != 0)
{
info->memory_error_func (status, pc, info);
return -1;
}
given = (b[0]) | (b[1] << 8) | (b[2] << 16) | (b[3] << 24);
} }
else else
given = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3]); {
status = info->read_memory_func
(pc & ~ 0x3, (bfd_byte *) &b[0], 4, info);
if (status != 0)
{
info->memory_error_func (status, pc, info);
return -1;
}
if (is_thumb)
{
if (pc & 0x2)
{
given = (b[2] << 8) | b[3];
status = info->read_memory_func
((pc + 4) & ~ 0x3, (bfd_byte *) b, 4, info);
if (status != 0)
{
info->memory_error_func (status, pc + 4, info);
return -1;
}
given |= (b[0] << 24) | (b[1] << 16);
}
else
given = (b[0] << 8) | b[1] | (b[2] << 24) | (b[3] << 16);
}
else
given = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3]);
}
if (is_thumb) if (is_thumb)
status = print_insn_thumb (pc, info, given); status = print_insn_thumb (pc, info, given);
else else
@ -947,73 +999,37 @@ print_insn_big_arm (pc, info)
return status; return status;
} }
int
print_insn_big_arm (pc, info)
bfd_vma pc;
struct disassemble_info * info;
{
return print_insn (pc, info, false);
}
int int
print_insn_little_arm (pc, info) print_insn_little_arm (pc, info)
bfd_vma pc; bfd_vma pc;
struct disassemble_info * info; struct disassemble_info * info;
{ {
unsigned char b[4]; return print_insn (pc, info, true);
long given; }
int status;
int is_thumb; void
print_arm_disassembler_options (FILE * stream)
if (info->disassembler_options) {
{ int i;
parse_disassembler_options (info->disassembler_options);
fprintf (stream, _("\n\
/* To avoid repeated parsing of the options, we remove it here. */ The following ARM specific disassembler options are supported for use with\n\
info->disassembler_options = NULL; the -M switch:\n"));
}
for (i = NUM_ARM_REGNAMES; i--;)
is_thumb = force_thumb; fprintf (stream, " reg-names-%s %*c%s\n",
regnames[i].name,
if (!is_thumb && info->symbols != NULL) 14 - strlen (regnames[i].name), ' ',
{ regnames[i].description);
if (bfd_asymbol_flavour (*info->symbols) == bfd_target_coff_flavour)
{ fprintf (stream, " force-thumb Assume all insns are Thumb insns\n");
coff_symbol_type * cs; fprintf (stream, " no-force-thumb Examine preceeding label to determine an insn's type\n\n");
cs = coffsymbol (*info->symbols);
is_thumb = ( cs->native->u.syment.n_sclass == C_THUMBEXT
|| cs->native->u.syment.n_sclass == C_THUMBSTAT
|| cs->native->u.syment.n_sclass == C_THUMBLABEL
|| cs->native->u.syment.n_sclass == C_THUMBEXTFUNC
|| cs->native->u.syment.n_sclass == C_THUMBSTATFUNC);
}
else if (bfd_asymbol_flavour (*info->symbols) == bfd_target_elf_flavour)
{
elf_symbol_type * es;
es = *(elf_symbol_type **)(info->symbols);
is_thumb = (ELF_ST_TYPE (es->internal_elf_sym.st_info) == STT_ARM_TFUNC)
|| (ELF_ST_TYPE (es->internal_elf_sym.st_info) == STT_ARM_16BIT);
}
}
info->bytes_per_chunk = 4;
info->display_endian = BFD_ENDIAN_LITTLE;
status = (*info->read_memory_func) (pc, (bfd_byte *) &b[0], 4, info);
if (status != 0 && is_thumb)
{
info->bytes_per_chunk = 2;
status = info->read_memory_func (pc, (bfd_byte *) b, 2, info);
b[3] = b[2] = 0;
}
if (status != 0)
{
info->memory_error_func (status, pc, info);
return -1;
}
given = (b[0]) | (b[1] << 8) | (b[2] << 16) | (b[3] << 24);
if (is_thumb)
status = print_insn_thumb (pc, info, given);
else
status = print_insn_arm (pc, info, given);
return status;
} }

View File

@ -255,5 +255,9 @@ disassembler (abfd)
void void
disassembler_usage (FILE * stream) disassembler_usage (FILE * stream)
{ {
#ifdef ARCH_arm
print_arm_disassembler_options (stream);
#endif
return; return;
} }