arm-dis.c revision 60484
160484Sobrien/* Instruction printing code for the ARM 260484Sobrien Copyright (C) 1994, 95, 96, 97, 98, 99, 2000 Free Software Foundation, Inc. 360484Sobrien Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org) 460484Sobrien Modification by James G. Smith (jsmith@cygnus.co.uk) 560484Sobrien 660484SobrienThis file is part of libopcodes. 760484Sobrien 860484SobrienThis program is free software; you can redistribute it and/or modify it under 960484Sobrienthe terms of the GNU General Public License as published by the Free 1060484SobrienSoftware Foundation; either version 2 of the License, or (at your option) 1160484Sobrienany later version. 1260484Sobrien 1360484SobrienThis program is distributed in the hope that it will be useful, but WITHOUT 1460484SobrienANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1560484SobrienFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 1660484Sobrienmore details. 1760484Sobrien 1860484SobrienYou should have received a copy of the GNU General Public License 1960484Sobrienalong with this program; if not, write to the Free Software 2060484SobrienFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 2160484Sobrien 2260484Sobrien#include "sysdep.h" 2360484Sobrien#include "dis-asm.h" 2460484Sobrien#define DEFINE_TABLE 2560484Sobrien#include "arm-opc.h" 2660484Sobrien#include "coff/internal.h" 2760484Sobrien#include "libcoff.h" 2860484Sobrien#include "opintl.h" 2960484Sobrien 3060484Sobrien/* FIXME: This shouldn't be done here */ 3160484Sobrien#include "elf-bfd.h" 3260484Sobrien#include "elf/internal.h" 3360484Sobrien#include "elf/arm.h" 3460484Sobrien 3560484Sobrien#ifndef streq 3660484Sobrien#define streq(a,b) (strcmp ((a), (b)) == 0) 3760484Sobrien#endif 3860484Sobrien 3960484Sobrien#ifndef strneq 4060484Sobrien#define strneq(a,b,n) (strncmp ((a), (b), (n)) == 0) 4160484Sobrien#endif 4260484Sobrien 4360484Sobrien#ifndef NUM_ELEM 4460484Sobrien#define NUM_ELEM(a) (sizeof (a) / sizeof (a)[0]) 4560484Sobrien#endif 4660484Sobrien 4760484Sobrienstatic char * arm_conditional[] = 4860484Sobrien{"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", 4960484Sobrien "hi", "ls", "ge", "lt", "gt", "le", "", "nv"}; 5060484Sobrien 5160484Sobrientypedef struct 5260484Sobrien{ 5360484Sobrien const char * name; 5460484Sobrien const char * description; 5560484Sobrien const char * reg_names[16]; 5660484Sobrien} 5760484Sobrienarm_regname; 5860484Sobrien 5960484Sobrienstatic arm_regname regnames[] = 6060484Sobrien{ 6160484Sobrien { "raw" , "Select raw register names", 6260484Sobrien { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}}, 6360484Sobrien { "std", "Select register names used in ARM's ISA documentation", 6460484Sobrien { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc" }}, 6560484Sobrien { "apcs", "Select register names used in the APCS", 6660484Sobrien { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "sl", "fp", "ip", "sp", "lr", "pc" }}, 6760484Sobrien { "atpcs", "Select register names used in the ATPCS", 6860484Sobrien { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "IP", "SP", "LR", "PC" }}, 6960484Sobrien { "special-atpcs", "Select special register names used in the ATPCS", 7060484Sobrien { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "WR", "v5", "SB", "SL", "FP", "IP", "SP", "LR", "PC" }} 7160484Sobrien}; 7260484Sobrien 7360484Sobrien/* Default to standard register name set. */ 7460484Sobrienstatic unsigned int regname_selected = 1; 7560484Sobrien 7660484Sobrien#define NUM_ARM_REGNAMES NUM_ELEM (regnames) 7760484Sobrien#define arm_regnames regnames[regname_selected].reg_names 7860484Sobrien 7960484Sobrienstatic boolean force_thumb = false; 8060484Sobrien 8160484Sobrienstatic char * arm_fp_const[] = 8260484Sobrien{"0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0"}; 8360484Sobrien 8460484Sobrienstatic char * arm_shift[] = 8560484Sobrien{"lsl", "lsr", "asr", "ror"}; 8660484Sobrien 8760484Sobrien/* Forward declarations. */ 8860484Sobrienstatic void arm_decode_shift PARAMS ((long, fprintf_ftype, void *)); 8960484Sobrienstatic int print_insn_arm PARAMS ((bfd_vma, struct disassemble_info *, long)); 9060484Sobrienstatic int print_insn_thumb PARAMS ((bfd_vma, struct disassemble_info *, long)); 9160484Sobrienstatic void parse_disassembler_options PARAMS ((char *)); 9260484Sobrienstatic int print_insn PARAMS ((bfd_vma, struct disassemble_info *, boolean)); 9360484Sobrienint get_arm_regname_num_options (void); 9460484Sobrienint set_arm_regname_option (int option); 9560484Sobrienint get_arm_regnames (int option, const char **setname, 9660484Sobrien const char **setdescription, 9760484Sobrien const char ***register_names); 9860484Sobrien 9960484Sobrien/* Functions. */ 10060484Sobrienint 10160484Sobrienget_arm_regname_num_options (void) 10260484Sobrien{ 10360484Sobrien return NUM_ARM_REGNAMES; 10460484Sobrien} 10560484Sobrien 10660484Sobrienint 10760484Sobrienset_arm_regname_option (int option) 10860484Sobrien{ 10960484Sobrien int old = regname_selected; 11060484Sobrien regname_selected = option; 11160484Sobrien return old; 11260484Sobrien} 11360484Sobrien 11460484Sobrienint 11560484Sobrienget_arm_regnames (int option, const char **setname, 11660484Sobrien const char **setdescription, 11760484Sobrien const char ***register_names) 11860484Sobrien{ 11960484Sobrien *setname = regnames[option].name; 12060484Sobrien *setdescription = regnames[option].description; 12160484Sobrien *register_names = regnames[option].reg_names; 12260484Sobrien return 16; 12360484Sobrien} 12460484Sobrien 12560484Sobrienstatic void 12660484Sobrienarm_decode_shift (given, func, stream) 12760484Sobrien long given; 12860484Sobrien fprintf_ftype func; 12960484Sobrien void * stream; 13060484Sobrien{ 13160484Sobrien func (stream, "%s", arm_regnames[given & 0xf]); 13260484Sobrien 13360484Sobrien if ((given & 0xff0) != 0) 13460484Sobrien { 13560484Sobrien if ((given & 0x10) == 0) 13660484Sobrien { 13760484Sobrien int amount = (given & 0xf80) >> 7; 13860484Sobrien int shift = (given & 0x60) >> 5; 13960484Sobrien 14060484Sobrien if (amount == 0) 14160484Sobrien { 14260484Sobrien if (shift == 3) 14360484Sobrien { 14460484Sobrien func (stream, ", rrx"); 14560484Sobrien return; 14660484Sobrien } 14760484Sobrien 14860484Sobrien amount = 32; 14960484Sobrien } 15060484Sobrien 15160484Sobrien func (stream, ", %s #%d", arm_shift[shift], amount); 15260484Sobrien } 15360484Sobrien else 15460484Sobrien func (stream, ", %s %s", arm_shift[(given & 0x60) >> 5], 15560484Sobrien arm_regnames[(given & 0xf00) >> 8]); 15660484Sobrien } 15760484Sobrien} 15860484Sobrien 15960484Sobrien/* Print one instruction from PC on INFO->STREAM. 16060484Sobrien Return the size of the instruction (always 4 on ARM). */ 16160484Sobrienstatic int 16260484Sobrienprint_insn_arm (pc, info, given) 16360484Sobrien bfd_vma pc; 16460484Sobrien struct disassemble_info * info; 16560484Sobrien long given; 16660484Sobrien{ 16760484Sobrien struct arm_opcode * insn; 16860484Sobrien void * stream = info->stream; 16960484Sobrien fprintf_ftype func = info->fprintf_func; 17060484Sobrien 17160484Sobrien for (insn = arm_opcodes; insn->assembler; insn++) 17260484Sobrien { 17360484Sobrien if ((given & insn->mask) == insn->value) 17460484Sobrien { 17560484Sobrien char * c; 17660484Sobrien 17760484Sobrien for (c = insn->assembler; *c; c++) 17860484Sobrien { 17960484Sobrien if (*c == '%') 18060484Sobrien { 18160484Sobrien switch (*++c) 18260484Sobrien { 18360484Sobrien case '%': 18460484Sobrien func (stream, "%%"); 18560484Sobrien break; 18660484Sobrien 18760484Sobrien case 'a': 18860484Sobrien if (((given & 0x000f0000) == 0x000f0000) 18960484Sobrien && ((given & 0x02000000) == 0)) 19060484Sobrien { 19160484Sobrien int offset = given & 0xfff; 19260484Sobrien 19360484Sobrien func (stream, "[pc"); 19460484Sobrien 19560484Sobrien if (given & 0x01000000) 19660484Sobrien { 19760484Sobrien if ((given & 0x00800000) == 0) 19860484Sobrien offset = - offset; 19960484Sobrien 20060484Sobrien /* pre-indexed */ 20160484Sobrien func (stream, ", #%x]", offset); 20260484Sobrien 20360484Sobrien offset += pc + 8; 20460484Sobrien 20560484Sobrien /* Cope with the possibility of write-back 20660484Sobrien being used. Probably a very dangerous thing 20760484Sobrien for the programmer to do, but who are we to 20860484Sobrien argue ? */ 20960484Sobrien if (given & 0x00200000) 21060484Sobrien func (stream, "!"); 21160484Sobrien } 21260484Sobrien else 21360484Sobrien { 21460484Sobrien /* Post indexed. */ 21560484Sobrien func (stream, "], #%x", offset); 21660484Sobrien 21760484Sobrien offset = pc + 8; /* ie ignore the offset. */ 21860484Sobrien } 21960484Sobrien 22060484Sobrien func (stream, "\t; "); 22160484Sobrien info->print_address_func (offset, info); 22260484Sobrien } 22360484Sobrien else 22460484Sobrien { 22560484Sobrien func (stream, "[%s", 22660484Sobrien arm_regnames[(given >> 16) & 0xf]); 22760484Sobrien if ((given & 0x01000000) != 0) 22860484Sobrien { 22960484Sobrien if ((given & 0x02000000) == 0) 23060484Sobrien { 23160484Sobrien int offset = given & 0xfff; 23260484Sobrien if (offset) 23360484Sobrien func (stream, ", %s#%d", 23460484Sobrien (((given & 0x00800000) == 0) 23560484Sobrien ? "-" : ""), offset); 23660484Sobrien } 23760484Sobrien else 23860484Sobrien { 23960484Sobrien func (stream, ", %s", 24060484Sobrien (((given & 0x00800000) == 0) 24160484Sobrien ? "-" : "")); 24260484Sobrien arm_decode_shift (given, func, stream); 24360484Sobrien } 24460484Sobrien 24560484Sobrien func (stream, "]%s", 24660484Sobrien ((given & 0x00200000) != 0) ? "!" : ""); 24760484Sobrien } 24860484Sobrien else 24960484Sobrien { 25060484Sobrien if ((given & 0x02000000) == 0) 25160484Sobrien { 25260484Sobrien int offset = given & 0xfff; 25360484Sobrien if (offset) 25460484Sobrien func (stream, "], %s#%d", 25560484Sobrien (((given & 0x00800000) == 0) 25660484Sobrien ? "-" : ""), offset); 25760484Sobrien else 25860484Sobrien func (stream, "]"); 25960484Sobrien } 26060484Sobrien else 26160484Sobrien { 26260484Sobrien func (stream, "], %s", 26360484Sobrien (((given & 0x00800000) == 0) 26460484Sobrien ? "-" : "")); 26560484Sobrien arm_decode_shift (given, func, stream); 26660484Sobrien } 26760484Sobrien } 26860484Sobrien } 26960484Sobrien break; 27060484Sobrien 27160484Sobrien case 's': 27260484Sobrien if ((given & 0x004f0000) == 0x004f0000) 27360484Sobrien { 27460484Sobrien /* PC relative with immediate offset. */ 27560484Sobrien int offset = ((given & 0xf00) >> 4) | (given & 0xf); 27660484Sobrien 27760484Sobrien if ((given & 0x00800000) == 0) 27860484Sobrien offset = -offset; 27960484Sobrien 28060484Sobrien func (stream, "[pc, #%x]\t; ", offset); 28160484Sobrien 28260484Sobrien (*info->print_address_func) 28360484Sobrien (offset + pc + 8, info); 28460484Sobrien } 28560484Sobrien else 28660484Sobrien { 28760484Sobrien func (stream, "[%s", 28860484Sobrien arm_regnames[(given >> 16) & 0xf]); 28960484Sobrien if ((given & 0x01000000) != 0) 29060484Sobrien { 29160484Sobrien /* Pre-indexed. */ 29260484Sobrien if ((given & 0x00400000) == 0x00400000) 29360484Sobrien { 29460484Sobrien /* Immediate. */ 29560484Sobrien int offset = ((given & 0xf00) >> 4) | (given & 0xf); 29660484Sobrien if (offset) 29760484Sobrien func (stream, ", %s#%d", 29860484Sobrien (((given & 0x00800000) == 0) 29960484Sobrien ? "-" : ""), offset); 30060484Sobrien } 30160484Sobrien else 30260484Sobrien { 30360484Sobrien /* Register. */ 30460484Sobrien func (stream, ", %s%s", 30560484Sobrien (((given & 0x00800000) == 0) 30660484Sobrien ? "-" : ""), 30760484Sobrien arm_regnames[given & 0xf]); 30860484Sobrien } 30960484Sobrien 31060484Sobrien func (stream, "]%s", 31160484Sobrien ((given & 0x00200000) != 0) ? "!" : ""); 31260484Sobrien } 31360484Sobrien else 31460484Sobrien { 31560484Sobrien /* Post-indexed. */ 31660484Sobrien if ((given & 0x00400000) == 0x00400000) 31760484Sobrien { 31860484Sobrien /* Immediate. */ 31960484Sobrien int offset = ((given & 0xf00) >> 4) | (given & 0xf); 32060484Sobrien if (offset) 32160484Sobrien func (stream, "], %s#%d", 32260484Sobrien (((given & 0x00800000) == 0) 32360484Sobrien ? "-" : ""), offset); 32460484Sobrien else 32560484Sobrien func (stream, "]"); 32660484Sobrien } 32760484Sobrien else 32860484Sobrien { 32960484Sobrien /* Register. */ 33060484Sobrien func (stream, "], %s%s", 33160484Sobrien (((given & 0x00800000) == 0) 33260484Sobrien ? "-" : ""), 33360484Sobrien arm_regnames[given & 0xf]); 33460484Sobrien } 33560484Sobrien } 33660484Sobrien } 33760484Sobrien break; 33860484Sobrien 33960484Sobrien case 'b': 34060484Sobrien (*info->print_address_func) 34160484Sobrien (BDISP (given) * 4 + pc + 8, info); 34260484Sobrien break; 34360484Sobrien 34460484Sobrien case 'c': 34560484Sobrien func (stream, "%s", 34660484Sobrien arm_conditional [(given >> 28) & 0xf]); 34760484Sobrien break; 34860484Sobrien 34960484Sobrien case 'm': 35060484Sobrien { 35160484Sobrien int started = 0; 35260484Sobrien int reg; 35360484Sobrien 35460484Sobrien func (stream, "{"); 35560484Sobrien for (reg = 0; reg < 16; reg++) 35660484Sobrien if ((given & (1 << reg)) != 0) 35760484Sobrien { 35860484Sobrien if (started) 35960484Sobrien func (stream, ", "); 36060484Sobrien started = 1; 36160484Sobrien func (stream, "%s", arm_regnames[reg]); 36260484Sobrien } 36360484Sobrien func (stream, "}"); 36460484Sobrien } 36560484Sobrien break; 36660484Sobrien 36760484Sobrien case 'o': 36860484Sobrien if ((given & 0x02000000) != 0) 36960484Sobrien { 37060484Sobrien int rotate = (given & 0xf00) >> 7; 37160484Sobrien int immed = (given & 0xff); 37260484Sobrien immed = (((immed << (32 - rotate)) 37360484Sobrien | (immed >> rotate)) & 0xffffffff); 37460484Sobrien func (stream, "#%d\t; 0x%x", immed, immed); 37560484Sobrien } 37660484Sobrien else 37760484Sobrien arm_decode_shift (given, func, stream); 37860484Sobrien break; 37960484Sobrien 38060484Sobrien case 'p': 38160484Sobrien if ((given & 0x0000f000) == 0x0000f000) 38260484Sobrien func (stream, "p"); 38360484Sobrien break; 38460484Sobrien 38560484Sobrien case 't': 38660484Sobrien if ((given & 0x01200000) == 0x00200000) 38760484Sobrien func (stream, "t"); 38860484Sobrien break; 38960484Sobrien 39060484Sobrien case 'h': 39160484Sobrien if ((given & 0x00000020) == 0x00000020) 39260484Sobrien func (stream, "h"); 39360484Sobrien else 39460484Sobrien func (stream, "b"); 39560484Sobrien break; 39660484Sobrien 39760484Sobrien case 'A': 39860484Sobrien func (stream, "[%s", arm_regnames [(given >> 16) & 0xf]); 39960484Sobrien if ((given & 0x01000000) != 0) 40060484Sobrien { 40160484Sobrien int offset = given & 0xff; 40260484Sobrien if (offset) 40360484Sobrien func (stream, ", %s#%d]%s", 40460484Sobrien ((given & 0x00800000) == 0 ? "-" : ""), 40560484Sobrien offset * 4, 40660484Sobrien ((given & 0x00200000) != 0 ? "!" : "")); 40760484Sobrien else 40860484Sobrien func (stream, "]"); 40960484Sobrien } 41060484Sobrien else 41160484Sobrien { 41260484Sobrien int offset = given & 0xff; 41360484Sobrien if (offset) 41460484Sobrien func (stream, "], %s#%d", 41560484Sobrien ((given & 0x00800000) == 0 ? "-" : ""), 41660484Sobrien offset * 4); 41760484Sobrien else 41860484Sobrien func (stream, "]"); 41960484Sobrien } 42060484Sobrien break; 42160484Sobrien 42260484Sobrien case 'C': 42360484Sobrien switch (given & 0x00090000) 42460484Sobrien { 42560484Sobrien default: 42660484Sobrien func (stream, "_???"); 42760484Sobrien break; 42860484Sobrien case 0x90000: 42960484Sobrien func (stream, "_all"); 43060484Sobrien break; 43160484Sobrien case 0x10000: 43260484Sobrien func (stream, "_ctl"); 43360484Sobrien break; 43460484Sobrien case 0x80000: 43560484Sobrien func (stream, "_flg"); 43660484Sobrien break; 43760484Sobrien } 43860484Sobrien break; 43960484Sobrien 44060484Sobrien case 'F': 44160484Sobrien switch (given & 0x00408000) 44260484Sobrien { 44360484Sobrien case 0: 44460484Sobrien func (stream, "4"); 44560484Sobrien break; 44660484Sobrien case 0x8000: 44760484Sobrien func (stream, "1"); 44860484Sobrien break; 44960484Sobrien case 0x00400000: 45060484Sobrien func (stream, "2"); 45160484Sobrien break; 45260484Sobrien default: 45360484Sobrien func (stream, "3"); 45460484Sobrien } 45560484Sobrien break; 45660484Sobrien 45760484Sobrien case 'P': 45860484Sobrien switch (given & 0x00080080) 45960484Sobrien { 46060484Sobrien case 0: 46160484Sobrien func (stream, "s"); 46260484Sobrien break; 46360484Sobrien case 0x80: 46460484Sobrien func (stream, "d"); 46560484Sobrien break; 46660484Sobrien case 0x00080000: 46760484Sobrien func (stream, "e"); 46860484Sobrien break; 46960484Sobrien default: 47060484Sobrien func (stream, _("<illegal precision>")); 47160484Sobrien break; 47260484Sobrien } 47360484Sobrien break; 47460484Sobrien case 'Q': 47560484Sobrien switch (given & 0x00408000) 47660484Sobrien { 47760484Sobrien case 0: 47860484Sobrien func (stream, "s"); 47960484Sobrien break; 48060484Sobrien case 0x8000: 48160484Sobrien func (stream, "d"); 48260484Sobrien break; 48360484Sobrien case 0x00400000: 48460484Sobrien func (stream, "e"); 48560484Sobrien break; 48660484Sobrien default: 48760484Sobrien func (stream, "p"); 48860484Sobrien break; 48960484Sobrien } 49060484Sobrien break; 49160484Sobrien case 'R': 49260484Sobrien switch (given & 0x60) 49360484Sobrien { 49460484Sobrien case 0: 49560484Sobrien break; 49660484Sobrien case 0x20: 49760484Sobrien func (stream, "p"); 49860484Sobrien break; 49960484Sobrien case 0x40: 50060484Sobrien func (stream, "m"); 50160484Sobrien break; 50260484Sobrien default: 50360484Sobrien func (stream, "z"); 50460484Sobrien break; 50560484Sobrien } 50660484Sobrien break; 50760484Sobrien 50860484Sobrien case '0': case '1': case '2': case '3': case '4': 50960484Sobrien case '5': case '6': case '7': case '8': case '9': 51060484Sobrien { 51160484Sobrien int bitstart = *c++ - '0'; 51260484Sobrien int bitend = 0; 51360484Sobrien while (*c >= '0' && *c <= '9') 51460484Sobrien bitstart = (bitstart * 10) + *c++ - '0'; 51560484Sobrien 51660484Sobrien switch (*c) 51760484Sobrien { 51860484Sobrien case '-': 51960484Sobrien c++; 52060484Sobrien 52160484Sobrien while (*c >= '0' && *c <= '9') 52260484Sobrien bitend = (bitend * 10) + *c++ - '0'; 52360484Sobrien 52460484Sobrien if (!bitend) 52560484Sobrien abort (); 52660484Sobrien 52760484Sobrien switch (*c) 52860484Sobrien { 52960484Sobrien case 'r': 53060484Sobrien { 53160484Sobrien long reg; 53260484Sobrien 53360484Sobrien reg = given >> bitstart; 53460484Sobrien reg &= (2 << (bitend - bitstart)) - 1; 53560484Sobrien 53660484Sobrien func (stream, "%s", arm_regnames[reg]); 53760484Sobrien } 53860484Sobrien break; 53960484Sobrien case 'd': 54060484Sobrien { 54160484Sobrien long reg; 54260484Sobrien 54360484Sobrien reg = given >> bitstart; 54460484Sobrien reg &= (2 << (bitend - bitstart)) - 1; 54560484Sobrien 54660484Sobrien func (stream, "%d", reg); 54760484Sobrien } 54860484Sobrien break; 54960484Sobrien case 'x': 55060484Sobrien { 55160484Sobrien long reg; 55260484Sobrien 55360484Sobrien reg = given >> bitstart; 55460484Sobrien reg &= (2 << (bitend - bitstart)) - 1; 55560484Sobrien 55660484Sobrien func (stream, "0x%08x", reg); 55760484Sobrien 55860484Sobrien /* Some SWI instructions have special 55960484Sobrien meanings. */ 56060484Sobrien if ((given & 0x0fffffff) == 0x0FF00000) 56160484Sobrien func (stream, "\t; IMB"); 56260484Sobrien else if ((given & 0x0fffffff) == 0x0FF00001) 56360484Sobrien func (stream, "\t; IMBRange"); 56460484Sobrien } 56560484Sobrien break; 56660484Sobrien case 'X': 56760484Sobrien { 56860484Sobrien long reg; 56960484Sobrien 57060484Sobrien reg = given >> bitstart; 57160484Sobrien reg &= (2 << (bitend - bitstart)) - 1; 57260484Sobrien 57360484Sobrien func (stream, "%01x", reg & 0xf); 57460484Sobrien } 57560484Sobrien break; 57660484Sobrien case 'f': 57760484Sobrien { 57860484Sobrien long reg; 57960484Sobrien 58060484Sobrien reg = given >> bitstart; 58160484Sobrien reg &= (2 << (bitend - bitstart)) - 1; 58260484Sobrien 58360484Sobrien if (reg > 7) 58460484Sobrien func (stream, "#%s", 58560484Sobrien arm_fp_const[reg & 7]); 58660484Sobrien else 58760484Sobrien func (stream, "f%d", reg); 58860484Sobrien } 58960484Sobrien break; 59060484Sobrien default: 59160484Sobrien abort (); 59260484Sobrien } 59360484Sobrien break; 59460484Sobrien 59560484Sobrien case '`': 59660484Sobrien c++; 59760484Sobrien if ((given & (1 << bitstart)) == 0) 59860484Sobrien func (stream, "%c", *c); 59960484Sobrien break; 60060484Sobrien case '\'': 60160484Sobrien c++; 60260484Sobrien if ((given & (1 << bitstart)) != 0) 60360484Sobrien func (stream, "%c", *c); 60460484Sobrien break; 60560484Sobrien case '?': 60660484Sobrien ++c; 60760484Sobrien if ((given & (1 << bitstart)) != 0) 60860484Sobrien func (stream, "%c", *c++); 60960484Sobrien else 61060484Sobrien func (stream, "%c", *++c); 61160484Sobrien break; 61260484Sobrien default: 61360484Sobrien abort (); 61460484Sobrien } 61560484Sobrien break; 61660484Sobrien 61760484Sobrien default: 61860484Sobrien abort (); 61960484Sobrien } 62060484Sobrien } 62160484Sobrien } 62260484Sobrien else 62360484Sobrien func (stream, "%c", *c); 62460484Sobrien } 62560484Sobrien return 4; 62660484Sobrien } 62760484Sobrien } 62860484Sobrien abort (); 62960484Sobrien} 63060484Sobrien 63160484Sobrien/* Print one instruction from PC on INFO->STREAM. 63260484Sobrien Return the size of the instruction. */ 63360484Sobrienstatic int 63460484Sobrienprint_insn_thumb (pc, info, given) 63560484Sobrien bfd_vma pc; 63660484Sobrien struct disassemble_info * info; 63760484Sobrien long given; 63860484Sobrien{ 63960484Sobrien struct thumb_opcode * insn; 64060484Sobrien void * stream = info->stream; 64160484Sobrien fprintf_ftype func = info->fprintf_func; 64260484Sobrien 64360484Sobrien for (insn = thumb_opcodes; insn->assembler; insn++) 64460484Sobrien { 64560484Sobrien if ((given & insn->mask) == insn->value) 64660484Sobrien { 64760484Sobrien char * c = insn->assembler; 64860484Sobrien 64960484Sobrien /* Special processing for Thumb 2 instruction BL sequence: */ 65060484Sobrien if (!*c) /* Check for empty (not NULL) assembler string. */ 65160484Sobrien { 65260484Sobrien info->bytes_per_chunk = 4; 65360484Sobrien info->bytes_per_line = 4; 65460484Sobrien 65560484Sobrien func (stream, "bl\t"); 65660484Sobrien 65760484Sobrien info->print_address_func (BDISP23 (given) * 2 + pc + 4, info); 65860484Sobrien return 4; 65960484Sobrien } 66060484Sobrien else 66160484Sobrien { 66260484Sobrien info->bytes_per_chunk = 2; 66360484Sobrien info->bytes_per_line = 4; 66460484Sobrien 66560484Sobrien given &= 0xffff; 66660484Sobrien 66760484Sobrien for (; *c; c++) 66860484Sobrien { 66960484Sobrien if (*c == '%') 67060484Sobrien { 67160484Sobrien int domaskpc = 0; 67260484Sobrien int domasklr = 0; 67360484Sobrien 67460484Sobrien switch (*++c) 67560484Sobrien { 67660484Sobrien case '%': 67760484Sobrien func (stream, "%%"); 67860484Sobrien break; 67960484Sobrien 68060484Sobrien case 'S': 68160484Sobrien { 68260484Sobrien long reg; 68360484Sobrien 68460484Sobrien reg = (given >> 3) & 0x7; 68560484Sobrien if (given & (1 << 6)) 68660484Sobrien reg += 8; 68760484Sobrien 68860484Sobrien func (stream, "%s", arm_regnames[reg]); 68960484Sobrien } 69060484Sobrien break; 69160484Sobrien 69260484Sobrien case 'D': 69360484Sobrien { 69460484Sobrien long reg; 69560484Sobrien 69660484Sobrien reg = given & 0x7; 69760484Sobrien if (given & (1 << 7)) 69860484Sobrien reg += 8; 69960484Sobrien 70060484Sobrien func (stream, "%s", arm_regnames[reg]); 70160484Sobrien } 70260484Sobrien break; 70360484Sobrien 70460484Sobrien case 'T': 70560484Sobrien func (stream, "%s", 70660484Sobrien arm_conditional [(given >> 8) & 0xf]); 70760484Sobrien break; 70860484Sobrien 70960484Sobrien case 'N': 71060484Sobrien if (given & (1 << 8)) 71160484Sobrien domasklr = 1; 71260484Sobrien /* Fall through. */ 71360484Sobrien case 'O': 71460484Sobrien if (*c == 'O' && (given & (1 << 8))) 71560484Sobrien domaskpc = 1; 71660484Sobrien /* Fall through. */ 71760484Sobrien case 'M': 71860484Sobrien { 71960484Sobrien int started = 0; 72060484Sobrien int reg; 72160484Sobrien 72260484Sobrien func (stream, "{"); 72360484Sobrien 72460484Sobrien /* It would be nice if we could spot 72560484Sobrien ranges, and generate the rS-rE format: */ 72660484Sobrien for (reg = 0; (reg < 8); reg++) 72760484Sobrien if ((given & (1 << reg)) != 0) 72860484Sobrien { 72960484Sobrien if (started) 73060484Sobrien func (stream, ", "); 73160484Sobrien started = 1; 73260484Sobrien func (stream, "%s", arm_regnames[reg]); 73360484Sobrien } 73460484Sobrien 73560484Sobrien if (domasklr) 73660484Sobrien { 73760484Sobrien if (started) 73860484Sobrien func (stream, ", "); 73960484Sobrien started = 1; 74060484Sobrien func (stream, arm_regnames[14] /* "lr" */); 74160484Sobrien } 74260484Sobrien 74360484Sobrien if (domaskpc) 74460484Sobrien { 74560484Sobrien if (started) 74660484Sobrien func (stream, ", "); 74760484Sobrien func (stream, arm_regnames[15] /* "pc" */); 74860484Sobrien } 74960484Sobrien 75060484Sobrien func (stream, "}"); 75160484Sobrien } 75260484Sobrien break; 75360484Sobrien 75460484Sobrien 75560484Sobrien case '0': case '1': case '2': case '3': case '4': 75660484Sobrien case '5': case '6': case '7': case '8': case '9': 75760484Sobrien { 75860484Sobrien int bitstart = *c++ - '0'; 75960484Sobrien int bitend = 0; 76060484Sobrien 76160484Sobrien while (*c >= '0' && *c <= '9') 76260484Sobrien bitstart = (bitstart * 10) + *c++ - '0'; 76360484Sobrien 76460484Sobrien switch (*c) 76560484Sobrien { 76660484Sobrien case '-': 76760484Sobrien { 76860484Sobrien long reg; 76960484Sobrien 77060484Sobrien c++; 77160484Sobrien while (*c >= '0' && *c <= '9') 77260484Sobrien bitend = (bitend * 10) + *c++ - '0'; 77360484Sobrien if (!bitend) 77460484Sobrien abort (); 77560484Sobrien reg = given >> bitstart; 77660484Sobrien reg &= (2 << (bitend - bitstart)) - 1; 77760484Sobrien switch (*c) 77860484Sobrien { 77960484Sobrien case 'r': 78060484Sobrien func (stream, "%s", arm_regnames[reg]); 78160484Sobrien break; 78260484Sobrien 78360484Sobrien case 'd': 78460484Sobrien func (stream, "%d", reg); 78560484Sobrien break; 78660484Sobrien 78760484Sobrien case 'H': 78860484Sobrien func (stream, "%d", reg << 1); 78960484Sobrien break; 79060484Sobrien 79160484Sobrien case 'W': 79260484Sobrien func (stream, "%d", reg << 2); 79360484Sobrien break; 79460484Sobrien 79560484Sobrien case 'a': 79660484Sobrien /* PC-relative address -- the bottom two 79760484Sobrien bits of the address are dropped 79860484Sobrien before the calculation. */ 79960484Sobrien info->print_address_func 80060484Sobrien (((pc + 4) & ~3) + (reg << 2), info); 80160484Sobrien break; 80260484Sobrien 80360484Sobrien case 'x': 80460484Sobrien func (stream, "0x%04x", reg); 80560484Sobrien break; 80660484Sobrien 80760484Sobrien case 'I': 80860484Sobrien reg = ((reg ^ (1 << bitend)) - (1 << bitend)); 80960484Sobrien func (stream, "%d", reg); 81060484Sobrien break; 81160484Sobrien 81260484Sobrien case 'B': 81360484Sobrien reg = ((reg ^ (1 << bitend)) - (1 << bitend)); 81460484Sobrien (*info->print_address_func) 81560484Sobrien (reg * 2 + pc + 4, info); 81660484Sobrien break; 81760484Sobrien 81860484Sobrien default: 81960484Sobrien abort (); 82060484Sobrien } 82160484Sobrien } 82260484Sobrien break; 82360484Sobrien 82460484Sobrien case '\'': 82560484Sobrien c++; 82660484Sobrien if ((given & (1 << bitstart)) != 0) 82760484Sobrien func (stream, "%c", *c); 82860484Sobrien break; 82960484Sobrien 83060484Sobrien case '?': 83160484Sobrien ++c; 83260484Sobrien if ((given & (1 << bitstart)) != 0) 83360484Sobrien func (stream, "%c", *c++); 83460484Sobrien else 83560484Sobrien func (stream, "%c", *++c); 83660484Sobrien break; 83760484Sobrien 83860484Sobrien default: 83960484Sobrien abort (); 84060484Sobrien } 84160484Sobrien } 84260484Sobrien break; 84360484Sobrien 84460484Sobrien default: 84560484Sobrien abort (); 84660484Sobrien } 84760484Sobrien } 84860484Sobrien else 84960484Sobrien func (stream, "%c", *c); 85060484Sobrien } 85160484Sobrien } 85260484Sobrien return 2; 85360484Sobrien } 85460484Sobrien } 85560484Sobrien 85660484Sobrien /* No match. */ 85760484Sobrien abort (); 85860484Sobrien} 85960484Sobrien 86060484Sobrien/* Parse an individual disassembler option. */ 86160484Sobrienvoid 86260484Sobrienparse_arm_disassembler_option (option) 86360484Sobrien char * option; 86460484Sobrien{ 86560484Sobrien if (option == NULL) 86660484Sobrien return; 86760484Sobrien 86860484Sobrien if (strneq (option, "reg-names-", 10)) 86960484Sobrien { 87060484Sobrien int i; 87160484Sobrien 87260484Sobrien option += 10; 87360484Sobrien 87460484Sobrien for (i = NUM_ARM_REGNAMES; i--;) 87560484Sobrien if (streq (option, regnames[i].name)) 87660484Sobrien { 87760484Sobrien regname_selected = i; 87860484Sobrien break; 87960484Sobrien } 88060484Sobrien 88160484Sobrien if (i < 0) 88260484Sobrien fprintf (stderr, _("Unrecognised register name set: %s\n"), option); 88360484Sobrien } 88460484Sobrien else if (streq (option, "force-thumb")) 88560484Sobrien force_thumb = 1; 88660484Sobrien else if (streq (option, "no-force-thumb")) 88760484Sobrien force_thumb = 0; 88860484Sobrien else 88960484Sobrien fprintf (stderr, _("Unrecognised disassembler option: %s\n"), option); 89060484Sobrien 89160484Sobrien return; 89260484Sobrien} 89360484Sobrien 89460484Sobrien/* Parse the string of disassembler options, spliting it at whitespaces. */ 89560484Sobrienstatic void 89660484Sobrienparse_disassembler_options (options) 89760484Sobrien char * options; 89860484Sobrien{ 89960484Sobrien char * space; 90060484Sobrien 90160484Sobrien if (options == NULL) 90260484Sobrien return; 90360484Sobrien 90460484Sobrien do 90560484Sobrien { 90660484Sobrien space = strchr (options, ' '); 90760484Sobrien 90860484Sobrien if (space) 90960484Sobrien { 91060484Sobrien * space = '\0'; 91160484Sobrien parse_arm_disassembler_option (options); 91260484Sobrien * space = ' '; 91360484Sobrien options = space + 1; 91460484Sobrien } 91560484Sobrien else 91660484Sobrien parse_arm_disassembler_option (options); 91760484Sobrien } 91860484Sobrien while (space); 91960484Sobrien} 92060484Sobrien 92160484Sobrien/* NOTE: There are no checks in these routines that 92260484Sobrien the relevant number of data bytes exist. */ 92360484Sobrienstatic int 92460484Sobrienprint_insn (pc, info, little) 92560484Sobrien bfd_vma pc; 92660484Sobrien struct disassemble_info * info; 92760484Sobrien boolean little; 92860484Sobrien{ 92960484Sobrien unsigned char b[4]; 93060484Sobrien long given; 93160484Sobrien int status; 93260484Sobrien int is_thumb; 93360484Sobrien 93460484Sobrien if (info->disassembler_options) 93560484Sobrien { 93660484Sobrien parse_disassembler_options (info->disassembler_options); 93760484Sobrien 93860484Sobrien /* To avoid repeated parsing of these options, we remove them here. */ 93960484Sobrien info->disassembler_options = NULL; 94060484Sobrien } 94160484Sobrien 94260484Sobrien is_thumb = force_thumb; 94360484Sobrien 94460484Sobrien if (!is_thumb && info->symbols != NULL) 94560484Sobrien { 94660484Sobrien if (bfd_asymbol_flavour (*info->symbols) == bfd_target_coff_flavour) 94760484Sobrien { 94860484Sobrien coff_symbol_type * cs; 94960484Sobrien 95060484Sobrien cs = coffsymbol (*info->symbols); 95160484Sobrien is_thumb = ( cs->native->u.syment.n_sclass == C_THUMBEXT 95260484Sobrien || cs->native->u.syment.n_sclass == C_THUMBSTAT 95360484Sobrien || cs->native->u.syment.n_sclass == C_THUMBLABEL 95460484Sobrien || cs->native->u.syment.n_sclass == C_THUMBEXTFUNC 95560484Sobrien || cs->native->u.syment.n_sclass == C_THUMBSTATFUNC); 95660484Sobrien } 95760484Sobrien else if (bfd_asymbol_flavour (*info->symbols) == bfd_target_elf_flavour) 95860484Sobrien { 95960484Sobrien elf_symbol_type * es; 96060484Sobrien unsigned int type; 96160484Sobrien 96260484Sobrien es = *(elf_symbol_type **)(info->symbols); 96360484Sobrien type = ELF_ST_TYPE (es->internal_elf_sym.st_info); 96460484Sobrien 96560484Sobrien is_thumb = (type == STT_ARM_TFUNC) || (type == STT_ARM_16BIT); 96660484Sobrien } 96760484Sobrien } 96860484Sobrien 96960484Sobrien info->bytes_per_chunk = 4; 97060484Sobrien info->display_endian = little ? BFD_ENDIAN_LITTLE : BFD_ENDIAN_BIG; 97160484Sobrien 97260484Sobrien if (little) 97360484Sobrien { 97460484Sobrien status = info->read_memory_func (pc, (bfd_byte *) &b[0], 4, info); 97560484Sobrien if (status != 0 && is_thumb) 97660484Sobrien { 97760484Sobrien info->bytes_per_chunk = 2; 97860484Sobrien 97960484Sobrien status = info->read_memory_func (pc, (bfd_byte *) b, 2, info); 98060484Sobrien b[3] = b[2] = 0; 98160484Sobrien } 98260484Sobrien 98360484Sobrien if (status != 0) 98460484Sobrien { 98560484Sobrien info->memory_error_func (status, pc, info); 98660484Sobrien return -1; 98760484Sobrien } 98860484Sobrien 98960484Sobrien given = (b[0]) | (b[1] << 8) | (b[2] << 16) | (b[3] << 24); 99060484Sobrien } 99160484Sobrien else 99260484Sobrien { 99360484Sobrien status = info->read_memory_func 99460484Sobrien (pc & ~ 0x3, (bfd_byte *) &b[0], 4, info); 99560484Sobrien if (status != 0) 99660484Sobrien { 99760484Sobrien info->memory_error_func (status, pc, info); 99860484Sobrien return -1; 99960484Sobrien } 100060484Sobrien 100160484Sobrien if (is_thumb) 100260484Sobrien { 100360484Sobrien if (pc & 0x2) 100460484Sobrien { 100560484Sobrien given = (b[2] << 8) | b[3]; 100660484Sobrien 100760484Sobrien status = info->read_memory_func 100860484Sobrien ((pc + 4) & ~ 0x3, (bfd_byte *) b, 4, info); 100960484Sobrien if (status != 0) 101060484Sobrien { 101160484Sobrien info->memory_error_func (status, pc + 4, info); 101260484Sobrien return -1; 101360484Sobrien } 101460484Sobrien 101560484Sobrien given |= (b[0] << 24) | (b[1] << 16); 101660484Sobrien } 101760484Sobrien else 101860484Sobrien given = (b[0] << 8) | b[1] | (b[2] << 24) | (b[3] << 16); 101960484Sobrien } 102060484Sobrien else 102160484Sobrien given = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3]); 102260484Sobrien } 102360484Sobrien 102460484Sobrien if (is_thumb) 102560484Sobrien status = print_insn_thumb (pc, info, given); 102660484Sobrien else 102760484Sobrien status = print_insn_arm (pc, info, given); 102860484Sobrien 102960484Sobrien return status; 103060484Sobrien} 103160484Sobrien 103260484Sobrienint 103360484Sobrienprint_insn_big_arm (pc, info) 103460484Sobrien bfd_vma pc; 103560484Sobrien struct disassemble_info * info; 103660484Sobrien{ 103760484Sobrien return print_insn (pc, info, false); 103860484Sobrien} 103960484Sobrien 104060484Sobrienint 104160484Sobrienprint_insn_little_arm (pc, info) 104260484Sobrien bfd_vma pc; 104360484Sobrien struct disassemble_info * info; 104460484Sobrien{ 104560484Sobrien return print_insn (pc, info, true); 104660484Sobrien} 104760484Sobrien 104860484Sobrienvoid 104960484Sobrienprint_arm_disassembler_options (FILE * stream) 105060484Sobrien{ 105160484Sobrien int i; 105260484Sobrien 105360484Sobrien fprintf (stream, _("\n\ 105460484SobrienThe following ARM specific disassembler options are supported for use with\n\ 105560484Sobrienthe -M switch:\n")); 105660484Sobrien 105760484Sobrien for (i = NUM_ARM_REGNAMES; i--;) 105860484Sobrien fprintf (stream, " reg-names-%s %*c%s\n", 105960484Sobrien regnames[i].name, 106060484Sobrien 14 - strlen (regnames[i].name), ' ', 106160484Sobrien regnames[i].description); 106260484Sobrien 106360484Sobrien fprintf (stream, " force-thumb Assume all insns are Thumb insns\n"); 106460484Sobrien fprintf (stream, " no-force-thumb Examine preceeding label to determine an insn's type\n\n"); 106560484Sobrien} 1066