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