X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=opcodes%2Fm68k-dis.c;h=b9d8a0471cb93a059fac47f154c00d10e7d02d47;hb=e8d39116d246de9cfdaaa8b2844a8016a86eafc8;hp=5e4150d05ed8e59d7cb1f05c67c5326a63bf04a9;hpb=dc82c973b37a3ef26595f75024c49108c7738d0a;p=deliverable%2Fbinutils-gdb.git diff --git a/opcodes/m68k-dis.c b/opcodes/m68k-dis.c index 5e4150d05e..b9d8a0471c 100644 --- a/opcodes/m68k-dis.c +++ b/opcodes/m68k-dis.c @@ -1,17 +1,19 @@ /* Print Motorola 68k instructions. Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, - 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 + 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. - This file is free software; you can redistribute it and/or modify + This file is part of the GNU opcodes library. + + This library is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + the Free Software Foundation; either version 3, or (at your option) + any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + It is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software @@ -280,6 +282,11 @@ fetch_arg (unsigned char *buffer, val = (buffer[1] >> 6); break; + case 'E': + FETCH_DATA (info, buffer + 3); + val = (buffer[2] >> 1); + break; + case 'm': val = (buffer[1] & 0x40 ? 0x8 : 0) | ((buffer[0] >> 1) & 0x7) @@ -310,29 +317,8 @@ fetch_arg (unsigned char *buffer, abort (); } - switch (bits) - { - case 1: - return val & 1; - case 2: - return val & 3; - case 3: - return val & 7; - case 4: - return val & 017; - case 5: - return val & 037; - case 6: - return val & 077; - case 7: - return val & 0177; - case 8: - return val & 0377; - case 12: - return val & 07777; - default: - abort (); - } + /* bits is never too big. */ + return val & ((1 << bits) - 1); } /* Check if an EA is valid for a particular code. This is required @@ -645,12 +631,17 @@ print_insn_arg (const char *d, {"%dtt0",0x006}, {"%dtt1",0x007}, {"%buscr",0x008}, {"%usp", 0x800}, {"%vbr", 0x801}, {"%caar", 0x802}, {"%msp", 0x803}, {"%isp", 0x804}, - {"%flashbar", 0xc04}, {"%rambar", 0xc05}, /* mcf528x added these. */ + /* reg c04 is sometimes called flashbar or rambar. + rec c05 is also sometimes called rambar. */ + {"%rambar0", 0xc04}, {"%rambar1", 0xc05}, /* Should we be calling this psr like we do in case 'Y'? */ {"%mmusr",0x805}, - {"%urp", 0x806}, {"%srp", 0x807}, {"%pcr", 0x808}}; + {"%urp", 0x806}, {"%srp", 0x807}, {"%pcr", 0x808}, + + /* Fido added these. */ + {"%cac", 0xffe}, {"%mbb", 0xfff}}; val = fetch_arg (buffer, place, 12, info); for (regno = sizeof names / sizeof names[0] - 1; regno >= 0; regno--) @@ -680,6 +671,16 @@ print_insn_arg (const char *d, (*info->fprintf_func) (info->stream, "#%d", val); break; + case 'j': + val = fetch_arg (buffer, place, 3, info); + (*info->fprintf_func) (info->stream, "#%d", val+1); + break; + + case 'K': + val = fetch_arg (buffer, place, 9, info); + (*info->fprintf_func) (info->stream, "#%d", val); + break; + case 'M': if (place == 'h') { @@ -1204,18 +1205,22 @@ print_insn_arg (const char *d, static int match_insn_m68k (bfd_vma memaddr, disassemble_info * info, - const struct m68k_opcode * best, - struct private * priv) + const struct m68k_opcode * best) { unsigned char *save_p; unsigned char *p; const char *d; + const char *args = best->args; + struct private *priv = (struct private *) info->private_data; bfd_byte *buffer = priv->the_buffer; fprintf_ftype save_printer = info->fprintf_func; void (* save_print_address) (bfd_vma, struct disassemble_info *) = info->print_address_func; + if (*args == '.') + args++; + /* Point at first word of argument data, and at descriptor for first argument. */ p = buffer + 2; @@ -1224,7 +1229,7 @@ match_insn_m68k (bfd_vma memaddr, The only place this is stored in the opcode table is in the arguments--look for arguments which specify fields in the 2nd or 3rd words of the instruction. */ - for (d = best->args; *d; d += 2) + for (d = args; *d; d += 2) { /* I don't think it is necessary to be checking d[0] here; I suspect all this could be moved to the case statement below. */ @@ -1271,8 +1276,8 @@ match_insn_m68k (bfd_vma memaddr, three words long. */ if (p - buffer < 6 && (best->match & 0xffff) == 0xffff - && best->args[0] == '#' - && best->args[1] == 'w') + && args[0] == '#' + && args[1] == 'w') { /* Copy the one word argument into the usual location for a one word argument, to simplify printing it. We can get away with @@ -1286,15 +1291,13 @@ match_insn_m68k (bfd_vma memaddr, FETCH_DATA (info, p); - d = best->args; - save_p = p; info->print_address_func = dummy_print_address; info->fprintf_func = (fprintf_ftype) dummy_printer; /* We scan the operands twice. The first time we don't print anything, but look for errors. */ - for (; *d; d += 2) + for (d = args; *d; d += 2) { int eaten = print_insn_arg (d, buffer, p, memaddr + (p - buffer), info); @@ -1308,12 +1311,14 @@ match_insn_m68k (bfd_vma memaddr, } else { + /* We must restore the print functions before trying to print the + error message. */ + info->fprintf_func = save_printer; + info->print_address_func = save_print_address; info->fprintf_func (info->stream, /* xgettext:c-format */ _("\n"), best->name, best->args); - info->fprintf_func = save_printer; - info->print_address_func = save_print_address; return 2; } } @@ -1322,7 +1327,7 @@ match_insn_m68k (bfd_vma memaddr, info->fprintf_func = save_printer; info->print_address_func = save_print_address; - d = best->args; + d = args; info->fprintf_func (info->stream, "%s", best->name); @@ -1341,21 +1346,24 @@ match_insn_m68k (bfd_vma memaddr, return p - buffer; } -/* Print the m68k instruction at address MEMADDR in debugged memory, - on INFO->STREAM. Returns length of the instruction, in bytes. */ +/* Try to interpret the instruction at address MEMADDR as one that + can execute on a processor with the features given by ARCH_MASK. + If successful, print the instruction to INFO->STREAM and return + its length in bytes. Return 0 otherwise. */ -int -print_insn_m68k (bfd_vma memaddr, disassemble_info *info) +static int +m68k_scan_mask (bfd_vma memaddr, disassemble_info *info, + unsigned int arch_mask) { int i; const char *d; - unsigned int arch_mask; - struct private priv; - bfd_byte *buffer = priv.the_buffer; - int major_opcode; - static int numopcodes[16]; static const struct m68k_opcode **opcodes[16]; + static int numopcodes[16]; int val; + int major_opcode; + + struct private *priv = (struct private *) info->private_data; + bfd_byte *buffer = priv->the_buffer; if (!opcodes[0]) { @@ -1383,72 +1391,6 @@ print_insn_m68k (bfd_vma memaddr, disassemble_info *info) *opc_pointer[(m68k_opcodes[i].opcode >> 28) & 15]++ = &m68k_opcodes[i]; } - info->private_data = (PTR) &priv; - /* Tell objdump to use two bytes per chunk - and six bytes per line for displaying raw data. */ - info->bytes_per_chunk = 2; - info->bytes_per_line = 6; - info->display_endian = BFD_ENDIAN_BIG; - priv.max_fetched = priv.the_buffer; - priv.insn_start = memaddr; - - if (setjmp (priv.bailout) != 0) - /* Error return. */ - return -1; - - switch (info->mach) - { - default: - case 0: - arch_mask = (unsigned int) -1; - break; - case bfd_mach_m68000: - arch_mask = m68000|m68881|m68851; - break; - case bfd_mach_m68008: - arch_mask = m68008|m68881|m68851; - break; - case bfd_mach_m68010: - arch_mask = m68010|m68881|m68851; - break; - case bfd_mach_m68020: - arch_mask = m68020|m68881|m68851; - break; - case bfd_mach_m68030: - arch_mask = m68030|m68881|m68851; - break; - case bfd_mach_m68040: - arch_mask = m68040|m68881|m68851; - break; - case bfd_mach_m68060: - arch_mask = m68060|m68881|m68851; - break; - case bfd_mach_mcf5200: - arch_mask = mcfisa_a; - break; - case bfd_mach_mcf521x: - case bfd_mach_mcf528x: - arch_mask = mcfisa_a|mcfhwdiv|mcfisa_aa|mcfusp|mcfemac; - break; - case bfd_mach_mcf5206e: - arch_mask = mcfisa_a|mcfhwdiv|mcfmac; - break; - case bfd_mach_mcf5249: - arch_mask = mcfisa_a|mcfhwdiv|mcfemac; - break; - case bfd_mach_mcf5307: - arch_mask = mcfisa_a|mcfhwdiv|mcfmac; - break; - case bfd_mach_mcf5407: - arch_mask = mcfisa_a|mcfhwdiv|mcfisa_b|mcfmac; - break; - case bfd_mach_mcf547x: - case bfd_mach_mcf548x: - case bfd_mach_mcfv4e: - arch_mask = mcfisa_a|mcfhwdiv|mcfisa_b|mcfusp|cfloat|mcfemac; - break; - } - FETCH_DATA (info, buffer + 2); major_opcode = (buffer[0] >> 4) & 15; @@ -1457,6 +1399,10 @@ print_insn_m68k (bfd_vma memaddr, disassemble_info *info) const struct m68k_opcode *opc = opcodes[major_opcode][i]; unsigned long opcode = opc->opcode; unsigned long match = opc->match; + const char *args = opc->args; + + if (*args == '.') + args++; if (((0xff & buffer[0] & (match >> 24)) == (0xff & (opcode >> 24))) && ((0xff & buffer[1] & (match >> 16)) == (0xff & (opcode >> 16))) @@ -1472,7 +1418,7 @@ print_insn_m68k (bfd_vma memaddr, disassemble_info *info) /* Don't use for printout the variants of divul and divsl that have the same register number in two places. The more general variants will match instead. */ - for (d = opc->args; *d; d += 2) + for (d = args; *d; d += 2) if (d[1] == 'D') break; @@ -1480,7 +1426,7 @@ print_insn_m68k (bfd_vma memaddr, disassemble_info *info) point coprocessor instructions which use the same register number in two places, as above. */ if (*d == '\0') - for (d = opc->args; *d; d += 2) + for (d = args; *d; d += 2) if (d[1] == 't') break; @@ -1488,7 +1434,7 @@ print_insn_m68k (bfd_vma memaddr, disassemble_info *info) wait for fmoveml. */ if (*d == '\0') { - for (d = opc->args; *d; d += 2) + for (d = args; *d; d += 2) { if (d[0] == 's' && d[1] == '8') { @@ -1502,7 +1448,7 @@ print_insn_m68k (bfd_vma memaddr, disassemble_info *info) /* Don't match FPU insns with non-default coprocessor ID. */ if (*d == '\0') { - for (d = opc->args; *d; d += 2) + for (d = args; *d; d += 2) { if (d[0] == 'I') { @@ -1514,10 +1460,81 @@ print_insn_m68k (bfd_vma memaddr, disassemble_info *info) } if (*d == '\0') - if ((val = match_insn_m68k (memaddr, info, opc, & priv))) + if ((val = match_insn_m68k (memaddr, info, opc))) return val; } } + return 0; +} + +/* Print the m68k instruction at address MEMADDR in debugged memory, + on INFO->STREAM. Returns length of the instruction, in bytes. */ + +int +print_insn_m68k (bfd_vma memaddr, disassemble_info *info) +{ + unsigned int arch_mask; + struct private priv; + int val; + + bfd_byte *buffer = priv.the_buffer; + + /* Save these printing functions in case we need to restore them + later. */ + fprintf_ftype save_printer = info->fprintf_func; + void (* save_print_address) (bfd_vma, struct disassemble_info *) + = info->print_address_func; + + info->private_data = (PTR) &priv; + /* Tell objdump to use two bytes per chunk + and six bytes per line for displaying raw data. */ + info->bytes_per_chunk = 2; + info->bytes_per_line = 6; + info->display_endian = BFD_ENDIAN_BIG; + priv.max_fetched = priv.the_buffer; + priv.insn_start = memaddr; + + if (setjmp (priv.bailout) != 0) + { + /* longjmp may be called while these printing functions are + temporarily replaced with dummy functions. Restore them + before we leave. + + Admittedly, this save-and-restore operation is somewhat ugly + in that we are exposing the fact that match_insn_m68k + temporarily replaces insn->fprintf_func and + insn->print_address_func. Perhaps, a real fix is to report a + FETCH_DATA failure with a return value of some sort, without + using setjmp/longjmp. A better fix may be to teach the m68k + disassembler do its job without temporarily replacing + insn->fprintf_func and insn->print_address_func, but that's a + task for another day. */ + info->fprintf_func = save_printer; + info->print_address_func = save_print_address; + + /* Error return. */ + return -1; + } + + arch_mask = bfd_m68k_mach_to_features (info->mach); + if (!arch_mask) + { + /* First try printing an m680x0 instruction. Try printing a Coldfire + one if that fails. */ + val = m68k_scan_mask (memaddr, info, m68k_mask); + if (val) + return val; + + val = m68k_scan_mask (memaddr, info, mcf_mask); + if (val) + return val; + } + else + { + val = m68k_scan_mask (memaddr, info, arch_mask); + if (val) + return val; + } /* Handle undefined instructions. */ info->fprintf_func (info->stream, "0%o", (buffer[0] << 8) + buffer[1]);