X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=opcodes%2Farm-dis.c;h=7e9b3309008473243ffab5e54c110a40183185a0;hb=34b0f91d24c2668c92d68fefe418cb02bfcc97db;hp=f897292eb1b2d9be8d663a7fdac59a8666210541;hpb=6c082ed8061d0032492d47c7e52c1db5ecb9fde7;p=deliverable%2Fbinutils-gdb.git diff --git a/opcodes/arm-dis.c b/opcodes/arm-dis.c index f897292eb1..7e9b330900 100644 --- a/opcodes/arm-dis.c +++ b/opcodes/arm-dis.c @@ -1,5 +1,6 @@ /* Instruction printing code for the ARM - Copyright (C) 1994, 95, 96, 97, 98, 99, 2000 Free Software Foundation, Inc. + Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 + Free Software Foundation, Inc. Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org) Modification by James G. Smith (jsmith@cygnus.co.uk) @@ -60,17 +61,19 @@ static arm_regname regnames[] = { { "raw" , "Select raw register names", { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}}, + { "gcc", "Select register names used by GCC", + { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc" }}, { "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", + { "special-atpcs", "Select special register names used in the ATPCS", { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "WR", "v5", "SB", "SL", "FP", "IP", "SP", "LR", "PC" }} }; -/* Default to standard register name set. */ +/* Default to GCC register name set. */ static unsigned int regname_selected = 1; #define NUM_ARM_REGNAMES NUM_ELEM (regnames) @@ -90,8 +93,38 @@ 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 void parse_disassembler_options PARAMS ((char *)); static int print_insn PARAMS ((bfd_vma, struct disassemble_info *, boolean)); +int get_arm_regname_num_options (void); +int set_arm_regname_option (int option); +int get_arm_regnames (int option, const char **setname, + const char **setdescription, + const char ***register_names); /* Functions. */ +int +get_arm_regname_num_options (void) +{ + return NUM_ARM_REGNAMES; +} + +int +set_arm_regname_option (int option) +{ + int old = regname_selected; + regname_selected = option; + return old; +} + +int +get_arm_regnames (int option, const char **setname, + const char **setdescription, + const char ***register_names) +{ + *setname = regnames[option].name; + *setdescription = regnames[option].description; + *register_names = regnames[option].reg_names; + return 16; +} + static void arm_decode_shift (given, func, stream) long given; @@ -168,7 +201,7 @@ print_insn_arm (pc, info, given) offset = - offset; /* pre-indexed */ - func (stream, ", #%x]", offset); + func (stream, ", #%d]", offset); offset += pc + 8; @@ -182,7 +215,7 @@ print_insn_arm (pc, info, given) else { /* Post indexed. */ - func (stream, "], #%x", offset); + func (stream, "], #%d", offset); offset = pc + 8; /* ie ignore the offset. */ } @@ -247,7 +280,7 @@ print_insn_arm (pc, info, given) if ((given & 0x00800000) == 0) offset = -offset; - func (stream, "[pc, #%x]\t; ", offset); + func (stream, "[pc, #%d]\t; ", offset); (*info->print_address_func) (offset + pc + 8, info); @@ -357,13 +390,6 @@ print_insn_arm (pc, info, given) func (stream, "t"); break; - case 'h': - if ((given & 0x00000020) == 0x00000020) - func (stream, "h"); - else - func (stream, "b"); - break; - case 'A': func (stream, "[%s", arm_regnames [(given >> 16) & 0xf]); if ((given & 0x01000000) != 0) @@ -389,22 +415,58 @@ print_insn_arm (pc, info, given) } break; + case 'B': + /* Print ARM V5 BLX(1) address: pc+25 bits. */ + { + bfd_vma address; + bfd_vma offset = 0; + + if (given & 0x00800000) + /* Is signed, hi bits should be ones. */ + offset = (-1) ^ 0x00ffffff; + + /* Offset is (SignExtend(offset field)<<2). */ + offset += given & 0x00ffffff; + offset <<= 2; + address = offset + pc + 8; + + if (given & 0x01000000) + /* H bit allows addressing to 2-byte boundaries. */ + address += 2; + + info->print_address_func (address, info); + } + break; + + case 'I': + /* Print a Cirrus/DSP shift immediate. */ + /* Immediates are 7bit signed ints with bits 0..3 in + bits 0..3 of opcode and bits 4..6 in bits 5..7 + of opcode. */ + { + int imm; + + imm = (given & 0xf) | ((given & 0xe0) >> 1); + + /* Is ``imm'' a negative number? */ + if (imm & 0x40) + imm |= (-1 << 7); + + func (stream, "%d", imm); + } + + break; + case 'C': - switch (given & 0x00090000) - { - default: - func (stream, "_???"); - break; - case 0x90000: - func (stream, "_all"); - break; - case 0x10000: - func (stream, "_ctl"); - break; - case 0x80000: - func (stream, "_flg"); - break; - } + 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"); break; case 'F': @@ -561,7 +623,85 @@ print_insn_arm (pc, info, given) abort (); } break; - + + case 'y': + case 'z': + { + int single = *c == 'y'; + int regno; + + switch (bitstart) + { + case 4: /* Sm pair */ + func (stream, "{"); + /* Fall through. */ + case 0: /* Sm, Dm */ + regno = given & 0x0000000f; + if (single) + { + regno <<= 1; + regno += (given >> 5) & 1; + } + break; + + case 1: /* Sd, Dd */ + regno = (given >> 12) & 0x0000000f; + if (single) + { + regno <<= 1; + regno += (given >> 22) & 1; + } + break; + + case 2: /* Sn, Dn */ + regno = (given >> 16) & 0x0000000f; + if (single) + { + regno <<= 1; + regno += (given >> 7) & 1; + } + break; + + case 3: /* List */ + func (stream, "{"); + regno = (given >> 12) & 0x0000000f; + if (single) + { + regno <<= 1; + regno += (given >> 22) & 1; + } + break; + + + default: + abort (); + } + + func (stream, "%c%d", single ? 's' : 'd', regno); + + if (bitstart == 3) + { + int count = given & 0xff; + + if (single == 0) + count >>= 1; + + if (--count) + { + func (stream, "-%c%d", + single ? 's' : 'd', + regno + count); + } + + func (stream, "}"); + } + else if (bitstart == 4) + func (stream, ", %c%d}", single ? 's' : 'd', + regno + 1); + + break; + } + case '`': c++; if ((given & (1 << bitstart)) == 0) @@ -619,11 +759,32 @@ print_insn_thumb (pc, info, given) /* Special processing for Thumb 2 instruction BL sequence: */ if (!*c) /* Check for empty (not NULL) assembler string. */ { + long offset; + info->bytes_per_chunk = 4; info->bytes_per_line = 4; + + offset = BDISP23 (given); - func (stream, "bl\t"); - info->print_address_func (BDISP23 (given) * 2 + pc + 4, info); + if ((given & 0x10000000) == 0) + { + func (stream, "blx\t"); + + /* The spec says that bit 1 of the branch's destination + address comes from bit 1 of the instruction's + address and not from the offset in the instruction. */ + if (offset & 0x1) + { + /* func (stream, "*malformed!* "); */ + offset &= ~ 0x1; + } + + offset |= ((pc & 0x2) >> 1); + } + else + func (stream, "bl\t"); + + info->print_address_func (offset * 2 + pc + 4, info); return 4; } else @@ -706,14 +867,14 @@ print_insn_thumb (pc, info, given) if (started) func (stream, ", "); started = 1; - func (stream, "lr"); + func (stream, arm_regnames[14] /* "lr" */); } if (domaskpc) { if (started) func (stream, ", "); - func (stream, "pc"); + func (stream, arm_regnames[15] /* "pc" */); } func (stream, "}"); @@ -827,8 +988,8 @@ print_insn_thumb (pc, info, given) } /* Parse an individual disassembler option. */ -static void -parse_disassembler_option (option) +void +parse_arm_disassembler_option (option) char * option; { if (option == NULL) @@ -877,12 +1038,12 @@ parse_disassembler_options (options) if (space) { * space = '\0'; - parse_disassembler_option (options); + parse_arm_disassembler_option (options); * space = ' '; options = space + 1; } else - parse_disassembler_option (options); + parse_arm_disassembler_option (options); } while (space); } @@ -990,6 +1151,14 @@ print_insn (pc, info, little) given = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3]); } + if (info->flags & INSN_HAS_RELOC) + /* If the instruction has a reloc associated with it, then + the offset field in the instruction will actually be the + addend for the reloc. (We are using REL type relocs). + In such cases, we can ignore the pc when computing + addresses, since the addend is not currently pc-relative. */ + pc = 0; + if (is_thumb) status = print_insn_thumb (pc, info, given); else @@ -1026,7 +1195,7 @@ the -M switch:\n")); for (i = NUM_ARM_REGNAMES; i--;) fprintf (stream, " reg-names-%s %*c%s\n", regnames[i].name, - 14 - strlen (regnames[i].name), ' ', + (int)(14 - strlen (regnames[i].name)), ' ', regnames[i].description); fprintf (stream, " force-thumb Assume all insns are Thumb insns\n");