diff --git a/binutils/ChangeLog b/binutils/ChangeLog index 21767160c4..9ce07ec388 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,9 @@ +2005-03-21 Jan-Benedict Glaw + + * doc/binutils.texi: Document new VAX disassembler-specific option + -M entry:0xfooba8. + * NEWS: Mention the new option. + 2005-03-29 Anil Paranjpe * MAINTAINERS: Add myself as H8300 maintainer. diff --git a/binutils/NEWS b/binutils/NEWS index e083502dd1..4ab5a0870a 100644 --- a/binutils/NEWS +++ b/binutils/NEWS @@ -1,5 +1,8 @@ -*- text -*- +* Add "-M entry:" switch to objdump to specify a function entry address + when disassembling VAX binaries. + * Add "--globalize-symbol " and "--globalize-symbols " switches to objcopy to convert local symbols into global symbols. diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi index 0b558fbf59..48078675d3 100644 --- a/binutils/doc/binutils.texi +++ b/binutils/doc/binutils.texi @@ -1793,6 +1793,13 @@ rather than names, for the selected types of registers. You can list the available values of @var{ABI} and @var{ARCH} using the @option{--help} option. +For VAX, you can specify function entry addresses with @option{-M +entry:0xf00ba}. You can use this multiple times to properly +disassemble VAX binary files that don't contain symbol tables (like +ROM dumps). In these cases, the function entry mask would otherwise +be decoded as VAX instructions, which would probably lead the the rest +of the function being wrongly disassembled. + @item -p @itemx --private-headers Print information that is specific to the object file format. The exact diff --git a/binutils/testsuite/ChangeLog b/binutils/testsuite/ChangeLog index 0902adcd4b..bd490af861 100644 --- a/binutils/testsuite/ChangeLog +++ b/binutils/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2005-03-29 Jan-Benedict Glaw + + * binutils-all/vax: New directory. + * binutils-all/vax/objdump.exp: New script. Test the -Mentry: + switch added to the VAX disassembler. + * binutils-all/vax/entrymask.s: New assembler source file. + 2005-03-08 Ben Elliston * config/default.exp: Remove send_user call for stray output. diff --git a/binutils/testsuite/binutils-all/vax/entrymask.s b/binutils/testsuite/binutils-all/vax/entrymask.s new file mode 100644 index 0000000000..18f9010618 --- /dev/null +++ b/binutils/testsuite/binutils-all/vax/entrymask.s @@ -0,0 +1,11 @@ +.text + +.global label1 +label1: + .word 0x0110 + +.global label2 +.type label2,@function +label2: + .word 0x0224 + diff --git a/binutils/testsuite/binutils-all/vax/objdump.exp b/binutils/testsuite/binutils-all/vax/objdump.exp new file mode 100644 index 0000000000..dd81633246 --- /dev/null +++ b/binutils/testsuite/binutils-all/vax/objdump.exp @@ -0,0 +1,82 @@ +# +# Copyright 1993, 1994, 1995, 1997, 1999, 2000, 2002, 2005 +# Free Software Foundation, Inc. +# +# This program 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. +# +# 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. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +# +# This file was written by Jan-Benedict Glaw . It's goal +# is to check the VAX-specific support of the -M entry:0xf00 switch, which +# allows to force function entry masks at given addresses. +# + +if ![istarget vax*-*-*] then { + return +} + +if {[which $OBJDUMP] == 0} then { + perror "$OBJDUMP does not exist" + return +} + +send_user "Version [binutil_version $OBJDUMP]" + +if {![binutils_assemble $srcdir/$subdir/entrymask.s tmpdir/entrymask.o]} then { + return +} + +if [is_remote host] { + set objfile [remote_download host tmpdir/entrymask.o] +} else { + set objfile tmpdir/entrymask.o +} + +# +# First run. We expect the function to be a function and the sole label +# not to produce an entry mask. +# +set got [binutils_run $OBJDUMP "$OBJDUMPFLAGS -d $objfile"] +set want1 "\[ \]+0:\[ \]+10 01\[ \]+bsbb 3" +set want2 "\[ \]+2:\[ \]+24 02\[ \]+\\.word 0x0224.\*r9 r5 r2" +if [regexp $want1 $got] then { + pass "entrymask test 1" +} else { + fail "entrymask test 1" +} +if [regexp $want2 $got] then { + pass "entrymask test 2" +} else { + fail "entrymask test 2" +} + +# +# Second run. Now, we force the label as a function, so we expect that +# it also produces an entry mask, as any call'able function should. +# +set got [binutils_run $OBJDUMP "$OBJDUMPFLAGS -d -M entry:0x0 $objfile"] +set want3 "\[ \]+0:\[ \]+10 01\[ \]+\\.word 0x0110.\*r8 r4" +set want4 "\[ \]+2:\[ \]+24 02\[ \]+\\.word 0x0224.\*r9 r5 r2" +if [regexp $want3 $got] then { + pass "entrymask test 3" +} else { + fail "entrymask test 3" +} +if [regexp $want4 $got] then { + pass "entrymask test 4" +} else { + fail "entrymask test 4" +} + diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog index 38a17eb8fe..86eca6aaca 100644 --- a/opcodes/ChangeLog +++ b/opcodes/ChangeLog @@ -1,3 +1,21 @@ +2005-03-21 Jan-Benedict Glaw + Nick Clifton + + * vax-dis.c: (entry_addr): New varible: An array of user supplied + function entry mask addresses. + (entry_addr_occupied_slots): New variable: The number of occupied + elements in entry_addr. + (entry_addr_total_slots): New variable: The total number of + elements in entry_addr. + (parse_disassembler_options): New function. Fills in the entry_addr + array. + (free_entry_array): New function. Release the memory used by the + entry addr array. Suppressed because there is no way to call it. + (is_function_entry): Check if a given address is a function's + start address by looking at supplied entry mask addresses and + symbol information, if available. + (print_insn_vax): Use parse_disassembler_options and is_function_entry. + 2005-03-23 H.J. Lu * cris-dis.c (print_with_operands): Use ~31L for long instead diff --git a/opcodes/vax-dis.c b/opcodes/vax-dis.c index e8b8c2a674..1300f54484 100644 --- a/opcodes/vax-dis.c +++ b/opcodes/vax-dis.c @@ -17,6 +17,8 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include +#include #include "sysdep.h" #include "opcode/vax.h" #include "dis-asm.h" @@ -77,15 +79,13 @@ static char *entry_mask_bit[] = /* Maximum length of an instruction. */ #define MAXLEN 25 -#include - struct private { /* Points to first byte not fetched. */ - bfd_byte *max_fetched; - bfd_byte the_buffer[MAXLEN]; - bfd_vma insn_start; - jmp_buf bailout; + bfd_byte * max_fetched; + bfd_byte the_buffer[MAXLEN]; + bfd_vma insn_start; + jmp_buf bailout; }; /* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive) @@ -119,6 +119,95 @@ fetch_data (info, addr) return 1; } +/* Entry mask handling. */ +static unsigned int entry_addr_occupied_slots = 0; +static unsigned int entry_addr_total_slots = 0; +static bfd_vma * entry_addr = NULL; + +/* Parse the VAX specific disassembler options. These contain function + entry addresses, which can be useful to disassemble ROM images, since + there's no symbol table. Returns TRUE upon success, FALSE otherwise. */ + +static bfd_boolean +parse_disassembler_options (char * options) +{ + const char * entry_switch = "entry:"; + + while ((options = strstr (options, entry_switch))) + { + options += strlen (entry_switch); + + /* The greater-than part of the test below is paranoia. */ + if (entry_addr_occupied_slots >= entry_addr_total_slots) + { + /* A guesstimate of the number of entries we will have to create. */ + entry_addr_total_slots += + strlen (options) / (strlen (entry_switch) + 5); + + entry_addr = realloc (entry_addr, sizeof (bfd_vma) + * entry_addr_total_slots); + } + + if (entry_addr == NULL) + return FALSE; + + entry_addr[entry_addr_occupied_slots] = bfd_scan_vma (options, NULL, 0); + entry_addr_occupied_slots ++; + } + + return TRUE; +} + +#if 0 /* FIXME: Ideally the disassembler should have target specific + initialisation and termination function pointers. Then + parse_disassembler_options could be the init function and + free_entry_array (below) could be the termination routine. + Until then there is no way for the disassembler to tell us + that it has finished and that we no longer need the entry + array, so this routine is suppressed for now. It does mean + that we leak memory, but only to the extent that we do not + free it just before the disassembler is about to terminate + anyway. */ + +/* Free memory allocated to our entry array. */ + +static void +free_entry_array (void) +{ + if (entry_addr) + { + free (entry_addr); + entry_addr = NULL; + entry_addr_occupied_slots = entry_addr_total_slots = 0; + } +} +#endif +/* Check if the given address is a known function entry. Either there must + be a symbol of function type at this address, or the address must be + a forced entry point. The later helps in disassembling ROM images, because + there's no symbol table at all. Forced entry points can be given by + supplying several -M options to objdump: -M entry:0xffbb7730. */ + +static bfd_boolean +is_function_entry (struct disassemble_info *info, bfd_vma addr) +{ + unsigned int i; + + /* Check if there's a BSF_FUNCTION symbol at our address. */ + if (info->symbols + && info->symbols[0] + && (info->symbols[0]->flags & BSF_FUNCTION) + && addr == bfd_asymbol_value (info->symbols[0])) + return TRUE; + + /* Check for forced function entry address. */ + for (i = entry_addr_occupied_slots; i--;) + if (entry_addr[i] == addr) + return TRUE; + + return FALSE; +} + /* Print the vax instruction at address MEMADDR in debugged memory, on INFO->STREAM. Returns length of the instruction, in bytes. */ @@ -127,6 +216,7 @@ print_insn_vax (memaddr, info) bfd_vma memaddr; disassemble_info *info; { + static bfd_boolean parsed_disassembler_options = FALSE; const struct vot *votp; const char *argp; unsigned char *arg; @@ -137,6 +227,15 @@ print_insn_vax (memaddr, info) priv.max_fetched = priv.the_buffer; priv.insn_start = memaddr; + if (! parsed_disassembler_options + && info->disassembler_options != NULL) + { + parse_disassembler_options (info->disassembler_options); + + /* To avoid repeated parsing of these options. */ + parsed_disassembler_options = TRUE; + } + if (setjmp (priv.bailout) != 0) { /* Error return. */ @@ -157,10 +256,7 @@ print_insn_vax (memaddr, info) } /* Decode function entry mask. */ - if (info->symbols - && info->symbols[0] - && (info->symbols[0]->flags & BSF_FUNCTION) - && memaddr == bfd_asymbol_value (info->symbols[0])) + if (is_function_entry (info, memaddr)) { int i = 0; int register_mask = buffer[1] << 8 | buffer[0];