VAX: Forced decoding of function entry masks (eg. for disassembling ROM images)

Jan-Benedict Glaw jbglaw@microdata-pos.de
Mon Mar 21 22:01:00 GMT 2005


On Mon, Mar 21, 2005 at 03:31:54PM +0100, Andreas Schwab wrote:
> Jan-Benedict Glaw <jbglaw@microdata-pos.de> writes:
> > This was very useful for me and I'd like to get a comment if you think
> > it's worth importing into the binutils tree. (I'll then resubmit with a
> > changelog text). Basically, this patch shifts a bit of code around,
> > introduces a new function to decide wether an address is an entry mask
> > and another new function that sets up the disassembler-private array of
> > (up to 30) forced entry mask addresses.
> 
> Why only 30?  GNU programs should not have arbitrary fixed limits.

5 is most probably enough (as in "640KB fits them all":-) but I
wanted to actually not {m,re}alloc() memory to get a variable length
list, which implies the need to free() it afterwards. Though, here's
another patch:

2005-03-21  Jan-Benedict Glaw  <jbglaw@lug-owl.de>
	opcodes/
	* vax-dis.c: (struct private): Add a bfd_vma pointer to store
	supplied function entry mask addresses.
	(init_private_data): New; fill in supplied entry mask addresses.
	(free_private_data): New; free() entry mask addresses.
	(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 init_private_data(), is_function_entry()
	and free_private_data().

	binutils/doc/
	* binutils.texi: Document new VAX disassembler-specific option
	-M entry:0xfooba8.

diff -Nurp src-fresh/binutils/doc/binutils.texi src-hacked/binutils/doc/binutils.texi
--- src-fresh/binutils/doc/binutils.texi	2005-03-21 13:26:04.000000000 +0100
+++ src-hacked/binutils/doc/binutils.texi	2005-03-21 20:09:33.000000000 +0100
@@ -1793,6 +1793,13 @@ rather than names, for the selected type
 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 -Nurp src-fresh/opcodes/vax-dis.c src-hacked/opcodes/vax-dis.c
--- src-fresh/opcodes/vax-dis.c	2005-03-14 14:07:03.000000000 +0100
+++ src-hacked/opcodes/vax-dis.c	2005-03-21 16:29:49.000000000 +0100
@@ -17,17 +17,38 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
+#include <setjmp.h>
+#include <string.h>
 #include "sysdep.h"
 #include "opcode/vax.h"
 #include "dis-asm.h"
 
+/* Maximum length of an instruction.  */
+#define MAXLEN 25
+
+struct private
+{
+  /* Points to first byte not fetched.  */
+  bfd_byte *max_fetched;
+  bfd_byte the_buffer[MAXLEN];
+  bfd_vma insn_start;
+  jmp_buf bailout;
+  /* Entry mask handling  */
+  int num_entry_addr;
+  bfd_vma *entry_addr;
+};
+
 /* Local function prototypes */
 static int fetch_data PARAMS ((struct disassemble_info *, bfd_byte *));
 static int print_insn_arg
   PARAMS ((const char *, unsigned char *, bfd_vma, disassemble_info *));
 static int print_insn_mode
   PARAMS ((const char *, int, unsigned char *, bfd_vma, disassemble_info *));
-
+static int init_private_data
+  PARAMS ((struct disassemble_info *, struct private *));
+static void free_private_data PARAMS ((struct private *));
+static bfd_boolean is_function_entry
+  PARAMS ((struct disassemble_info *, bfd_vma addr));
 
 static char *reg_names[] =
 {
@@ -74,20 +95,6 @@ static char *entry_mask_bit[] =
   (p += 4, FETCH_DATA (info, p), \
    (COERCE32 ((((((p[-1] << 8) + p[-2]) << 8) + p[-3]) << 8) + p[-4])))
 
-/* Maximum length of an instruction.  */
-#define MAXLEN 25
-
-#include <setjmp.h>
-
-struct private
-{
-  /* Points to first byte not fetched.  */
-  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)
    to ADDR (exclusive) are valid.  Returns 1 for success, longjmps
    on error.  */
@@ -95,6 +102,74 @@ struct private
   ((addr) <= ((struct private *)(info->private_data))->max_fetched \
    ? 1 : fetch_data ((info), (addr)))
 
+
+/* Init our private data. This decodes supplied entry addresses, which can
+   be useful to disassemble ROM images, since there's no symbol table.  */
+static int
+init_private_data (info, priv)
+    struct disassemble_info *info;
+    struct private *priv;
+{
+  char *tmp;
+
+  priv->num_entry_addr = 0;
+  priv->entry_addr = NULL;
+
+  if (info->disassembler_options)
+    {
+      tmp = info->disassembler_options;
+      while ((tmp = strstr (tmp, "entry:")))
+	{
+	  tmp += strlen ("entry:");
+	  priv->entry_addr = realloc (priv->entry_addr, sizeof (bfd_vma)
+				      * (priv->num_entry_addr + 1));
+	  if (!priv->entry_addr)
+	    return -1;
+	  priv->entry_addr[priv->num_entry_addr++] = bfd_scan_vma (tmp, NULL,
+			  					   0);
+	}
+    }
+
+  return 0;
+}
+
+/* Free memory allocated by init_private_data()  */
+static void
+free_private_data (priv)
+    struct private *priv;
+{
+  if (priv->entry_addr)
+    free (priv->entry_addr);
+}
+
+/* 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 (info, addr)
+      struct disassemble_info *info;
+      bfd_vma addr;
+{
+  int i;
+  struct private *priv = info->private_data;
+
+  /* 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 = 0; i < priv->num_entry_addr; i++)
+    if (priv->entry_addr[i] == addr)
+      return TRUE;
+
+  return FALSE;
+}
+
 static int
 fetch_data (info, addr)
      struct disassemble_info *info;
@@ -133,6 +208,9 @@ print_insn_vax (memaddr, info)
   struct private priv;
   bfd_byte *buffer = priv.the_buffer;
 
+  if (init_private_data (info, &priv) < 0)
+    return -1;
+
   info->private_data = (PTR) &priv;
   priv.max_fetched = priv.the_buffer;
   priv.insn_start = memaddr;
@@ -140,6 +218,7 @@ print_insn_vax (memaddr, info)
   if (setjmp (priv.bailout) != 0)
     {
       /* Error return.  */
+      free_private_data (&priv);
       return -1;
     }
 
@@ -157,10 +236,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];
@@ -174,6 +250,7 @@ print_insn_vax (memaddr, info)
 
       (*info->fprintf_func) (info->stream, " >");
 
+      free_private_data (&priv);
       return 2;
     }
 
@@ -194,6 +271,7 @@ print_insn_vax (memaddr, info)
       /* Handle undefined instructions. */
       (*info->fprintf_func) (info->stream, ".word 0x%x",
 			     (buffer[0] << 8) + buffer[1]);
+      free_private_data (&priv);
       return 2;
     }
 
@@ -216,6 +294,7 @@ print_insn_vax (memaddr, info)
 	(*info->fprintf_func) (info->stream, ",");
     }
 
+  free_private_data (&priv);
   return arg - buffer;
 }
 

Thanks, JBG

-- 
AWEK microdata GmbH -- Am Wellbach 4 -- 33609 Bielefeld



More information about the Binutils mailing list