[PATCH] Add OSE operating system support [1/5] ose core format support of bfd

Hui Zhu hui_zhu@mentor.com
Fri Mar 8 13:29:00 GMT 2013


This patch adds the initial support for OSE core dumps.  The file
format is based on the IFF format <http://www.martinreddy.net/gfx/2d/IFF.txt>,
by Electronic Arts.  The EA guys were helpful and wrote a reference
IFF reader and placed it in the public domain.  Googling around,
it appears everyone based their readers on that code, so, we do too.
That code was originally written for the Amiga though, and isn't
the cleanest code around (not exactly library ready), so I ended up
importing what we needed into the bfd ose core backend implementation file,
massaging it to work with bfds, and fixing a couple of bugs, and adjusting
the formating/symbol names to make it sit nicely in the bfd mix.

So, the ose-core.c file contains both the core IFF reader, and, the
OSE PMD file parser, which uses the "generic" reader, to read a
core following the PMD file's grammar.

Thanks,
Hui

2013-03-08  Pedro Alves  <pedro@codesourcery.com>
	    Luis Machado  <lgustavo@codesourcery.com>

	* Makefile.am (BFD32_BACKENDS): Add ose-core.lo.
	(BFD32_BACKENDS_CFILES): Add ose-core.c.
	* bfd-in2.h (bfd): Add ose_core_data.
	* bfd.c (bfd): Ditto.
	* config.bfd: Add ose_core_big_vec and ose_core_little_vec.
	* configure: Ditto.
	* configure.in: Ditto.
	* ose-core.c: New.
	* targets.c: Add ose_core_big_vec and ose_core_little_vec.

On 03/05/13 17:57, Hui Zhu wrote:
> Hi,
>
> OSE's core file format is different compared to Linux, so there is patch for bfd to handle this format.
>
> Thanks,
> Hui
>
> 2013-03-05  Luis Machado  <lgustavo@codesourcery.com>
>
>      * Makefile.am (BFD32_BACKENDS): Add ose-core.lo.
>      (BFD32_BACKENDS_CFILES): Add ose-core.c.
>      * bfd-in2.h (bfd): Add ose_core_data.
>      * bfd.c (bfd): Ditto.
>      * config.bfd: Add ose_core_big_vec and ose_core_little_vec.
>      * configure: Ditto.
>      * configure.in: Ditto.
>      * ose-core.c: New.
>      * targets.c: Add ose_core_big_vec and ose_core_little_vec.


-------------- next part --------------
--- a/bfd/Makefile.am
+++ b/bfd/Makefile.am
@@ -445,7 +445,8 @@ BFD32_BACKENDS = \
 	xcofflink.lo \
 	xsym.lo \
 	xtensa-isa.lo \
-	xtensa-modules.lo
+	xtensa-modules.lo \
+	ose-core.lo
 
 BFD32_BACKENDS_CFILES = \
 	aout-adobe.c \
@@ -634,7 +635,8 @@ BFD32_BACKENDS_CFILES = \
 	xcofflink.c \
 	xsym.c \
 	xtensa-isa.c \
-	xtensa-modules.c
+	xtensa-modules.c \
+	ose-core.c
 
 # The .o files needed by all of the 64 bit vectors that are configured into
 # target_vector in targets.c if configured with --enable-targets=all
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -6041,6 +6041,7 @@ struct bfd
       struct lynx_core_struct *lynx_core_data;
       struct osf_core_struct *osf_core_data;
       struct cisco_core_struct *cisco_core_data;
+      struct ose_core_struct *ose_core_data;
       struct versados_data_struct *versados_data;
       struct netbsd_core_struct *netbsd_core_data;
       struct mach_o_data_struct *mach_o_data;
--- a/bfd/bfd.c
+++ b/bfd/bfd.c
@@ -256,6 +256,7 @@ CODE_FRAGMENT
 .      struct lynx_core_struct *lynx_core_data;
 .      struct osf_core_struct *osf_core_data;
 .      struct cisco_core_struct *cisco_core_data;
+.      struct ose_core_struct *ose_core_data;
 .      struct versados_data_struct *versados_data;
 .      struct netbsd_core_struct *netbsd_core_data;
 .      struct mach_o_data_struct *mach_o_data;
--- a/bfd/config.bfd
+++ b/bfd/config.bfd
@@ -1255,9 +1255,9 @@ case "${targ}" in
     ;;
   powerpc-*-*bsd* | powerpc-*-elf* | powerpc-*-sysv4* | powerpc-*-eabi* | \
   powerpc-*-solaris2* | powerpc-*-linux-* | powerpc-*-rtems* | \
-  powerpc-*-chorus*)
+  powerpc-*-chorus* | powerpc-*-ose)
     targ_defvec=bfd_elf32_powerpc_vec
-    targ_selvecs="rs6000coff_vec bfd_elf32_powerpcle_vec ppcboot_vec"
+    targ_selvecs="rs6000coff_vec bfd_elf32_powerpcle_vec ppcboot_vec ose_core_big_vec ose_core_little_vec"
     targ64_selvecs="bfd_elf64_powerpc_vec bfd_elf64_powerpcle_vec"
     ;;
   powerpc-*-kaos*)
--- a/bfd/configure
+++ b/bfd/configure
@@ -15528,6 +15528,9 @@ do
     cisco_core_big_vec)		tb="$tb cisco-core.lo" ;;
     cisco_core_little_vec)	tb="$tb cisco-core.lo" ;;
 
+    ose_core_big_vec)		tb="$tb ose-core.lo" ;;
+    ose_core_little_vec)	tb="$tb ose-core.lo" ;;
+
     "")			;;
     *) as_fn_error "*** unknown target vector $vec" "$LINENO" 5 ;;
     esac
--- a/bfd/configure.in
+++ b/bfd/configure.in
@@ -1025,6 +1025,9 @@ do
     cisco_core_big_vec)		tb="$tb cisco-core.lo" ;;
     cisco_core_little_vec)	tb="$tb cisco-core.lo" ;;
 
+    ose_core_big_vec)		tb="$tb ose-core.lo" ;;
+    ose_core_little_vec)	tb="$tb ose-core.lo" ;;
+
     "")			;;
     *) AC_MSG_ERROR(*** unknown target vector $vec) ;;
     esac
--- /dev/null
+++ b/bfd/ose-core.c
@@ -0,0 +1,1940 @@
+/* BFD back-end for OSE crash dumps.
+   Copyright 2012 Free Software Foundation, Inc.
+
+   This file is part of BFD, the Binary File Descriptor library.
+
+   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 3 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., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+#include "sysdep.h"
+#include "bfd.h"
+#include "libbfd.h"
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <string.h>
+
+#ifdef HAVE_ZLIB_H
+#include <zlib.h>
+#endif
+
+static int debug_ose_core;
+
+static void
+ose_debug (const char *fmt, ...)
+{
+  va_list ap;
+
+  if (!debug_ose_core)
+    return;
+
+  va_start (ap, fmt);
+  vfprintf (stderr, fmt, ap);
+  va_end (ap);
+}
+
+struct ose_core_struct
+{
+  /* FIXME: we aren't setting these anywhere yet.  */
+  int sig;
+  int bid;
+};
+
+/* Begin generic IFF reader.  This is based on the iff.h and iffr.c
+   files of the public domain generic IFF reader for the Amiga.  See
+   <http://www.martinreddy.net/gfx/2d/IFF.txt>.  Copies of this code
+   are found in the Fish disks.
+
+   The original IFF.H file contains the following header:  */
+
+/*--- begin original header --- */
+
+/*----------------------------------------------------------------------*/
+/* IFF.H  defs for IFF-85 Interchange Format Files.             10/8/85 */
+/*                                                                      */
+/* By Jerry Morrison and Steve Shaw, Electronic Arts.                   */
+/* This software is in the public domain.                               */
+/*----------------------------------------------------------------------*/
+
+/*--- end original header --- */
+
+/* This version has been bfd-ized, formatting fixed, function names
+   adjusted to be library compatible (it's not like the original is
+   maintained anyway), some unnecessary functions were removed, and a
+   few bugs fixed too.  */
+
+/* Status code result from an IFF procedure.  int, because it must be
+   type compatible with ID for iff_get_chunk_header.  */
+
+typedef int IFFP;
+
+/* Note that the error codes below are not legal IDs.  */
+
+/* Keep going...  */
+#define IFF_OKAY 0L
+
+/* As if there was a chunk at end of group.  */
+#define END_MARK (-1L)
+
+/* A client procedure returns this when it has READ enough.  It means
+   return through all levels.  File is Okay.  */
+#define IFF_DONE (-2L)
+
+/* The OS returned some error.  Ask the OS what it was.  */
+#define OS_ERROR (-3L)
+
+/* Not an IFF file.  */
+#define NOT_IFF (-4L)
+
+/* Tried to open file, DOS didn't find it.  */
+#define NO_FILE (-5L)
+
+/* Client made invalid request, for instance, asking for more bytes
+   than existed in chunk.*/
+#define CLIENT_ERROR (-6L)
+
+/* A client read proc complains about FORM semantics; e.g. valid IFF,
+   but missing a required chunk.  */
+#define BAD_FORM (-7L)
+
+/* Client asked to iff_read_bytes more bytes than left in the chunk.
+   Could be client bug or bad form.  */
+#define SHORT_CHUNK (-8L)
+
+/* mal-formed IFF file.  */
+#define BAD_IFF (-9L)
+
+#define LAST_ERROR BAD_IFF
+
+/* ---------- ID -------------------------------------------------------*/
+
+/* An ID is four printable ASCII chars but stored as a int for
+   efficient copy & compare.  */
+typedef int ID;
+
+/* Four-character IDentifier builder.  */
+#define MakeID(a,b,c,d)  (((long)(a))<<24L | ((long)(b))<<16L | (c)<<8 | (d))
+
+/* Standard group IDs.  A chunk with one of these IDs contains a
+   SubTypeID followed by zero or more chunks.  */
+#define FORM MakeID ('F','O','R','M')
+#define PROP MakeID ('P','R','O','P')
+#define LIST MakeID ('L','I','S','T')
+#define CAT  MakeID ('C','A','T',' ')
+#define FILLER MakeID (' ',' ',' ',' ')
+
+/* The IDs "FOR1".."FOR9", "LIS1".."LIS9", & "CAT1".."CAT9" are
+   reserved for future standardization.  */
+
+/* Pseudo-ID used internally by the chunk reader, meaning no current
+   chunk.  */
+#define NULL_CHUNK 0L
+
+/* ---------- Chunk ---------------------------------------------------- */
+
+/* All chunks start with a type ID and a count of the data bytes that
+   follow -- the chunk's "logical size" or "data size".  If that
+   number is odd, a 0 pad byte is written, too.  */
+
+typedef struct
+{
+  ID ID;
+  int size;
+} iff_chunk_header;
+
+/* Need to know whether a value is odd so can word-align.  */
+#define IS_ODD(a)   ((a) & 1)
+
+/* ---------- IFF Reader -----------------------------------------------*/
+
+struct _iff_group_context;
+
+/* Routines to support a stream-oriented IFF file reader.
+
+   These routines handle lots of details like error checking and
+   skipping over padding. They're also careful not to read past any
+   containing context.
+
+   These routines ASSUME they're the only ones reading from the file.
+   Client should check IFFP error codes. Don't press on after an
+   error!  These routines try to have no side effects in the error
+   case, except partial I/O is sometimes unavoidable.
+
+   All of these routines may return OS_ERROR. In that case, ask the OS
+   for the specific error code.
+
+   The overall scheme for the low level chunk reader is to open a
+   "group read context" with iff_open_read or iff_open_read_group,
+   read the chunks with iff_get_chunk_header (and its kin) and
+   iff_read_bytes, and close the context with iff_close_read_group.
+
+   The overall scheme for reading an IFF file is to use iff_read,
+   iff_read_list, and iff_read_cat to scan the file.  See those procedures,
+   and ClientProc (below).  */
+
+
+/* Client passes ptrs to procedures of this type to iff_read which
+   call them back to handle LISTs, FORMs, CATs, and PROPs.
+
+   Use the iff_group_context ptr when calling reader routines like
+   iff_get_chunk_header.  Look inside the iff_group_context ptr for
+   your iff_client_frame ptr.  You'll want to type cast it into a ptr
+   to your containing struct to get your private contextual data
+   (stacked property settings).  See below.  */
+
+typedef IFFP iff_group_client_proc (struct _iff_group_context *);
+
+/* Client's context for reading an IFF file or a group.
+
+   Client should actually make this the first component of a larger
+   struct (it's personal stack "frame") that has a field to store each
+   "interesting" property encountered.
+
+   Either initialize each such field to a global default or keep a
+   boolean indicating if you've read a property chunk into that field.
+
+   Your get_list and get_form procs should allocate a new "frame" and
+   copy the parent frame's contents. The get_prop procedure should
+   store into the frame allocated by get_list for the containing
+   LIST.  */
+
+typedef struct _iff_client_frame
+{
+  iff_group_client_proc *get_list;
+  iff_group_client_proc *get_prop;
+  iff_group_client_proc *get_form;
+  iff_group_client_proc *get_cat;
+  /* Client's own data follows; place to stack property settings.  */
+} iff_client_frame;
+
+/* Our context for reading a group chunk.  */
+typedef struct _iff_group_context
+{
+  /* Containing group; NULL => whole file.  */
+  struct _iff_group_context *parent;
+
+  /* Reader data & client's context state.  */
+  iff_client_frame *client_frame;
+
+  /* The bfd.  */
+  bfd *abfd;
+
+  /* The context's logical file position.  */
+  int position;
+
+  /* File-absolute context bound.  */
+  int bound;
+
+  /* Current chunk header.  See also Pseudo-IDs, above.  */
+  iff_chunk_header ck_hdr;
+
+  /* Group's subtype ID when reading. */
+  ID subtype;
+
+  /* Number of bytes read of current chunk's data.  */
+  int bytesSoFar;
+} iff_group_context;
+
+/* Computes the number of bytes not yet read from the current chunk,
+   given a group read context GC.  */
+#define CHUNK_MORE_BYTES(gc)  ((gc)->ck_hdr.size - (gc)->bytesSoFar)
+
+
+/* Low Level IFF Chunk Reader.  */
+
+/* Given an open file, open a read context spanning the whole file.
+   This is normally only called by iff_read.  This sets
+   new->client_frame = client_frame.  Assumes the context is allocated
+   by the caller but not initialized.  Assumes the caller doesn't
+   deallocate the context before calling iff_close_read_group.  Returns NOT_IFF
+   error if the file is too short for even a chunk header.  */
+static IFFP iff_open_read (bfd *file, iff_group_context *, iff_client_frame *);
+
+/* Open the remainder of the current chunk as a group read context.
+   This will be called just after the group's subtype ID has been read
+   (automatically by iff_get_chunk_header for LIST, FORM, PROP, and CAT) so the
+   remainder is a sequence of chunks.
+
+   This sets new->client_frame = parent->client_frame. The caller should
+   re-point it at a new client_frame if opening a LIST context so it'll
+   have a "stack frame" to store PROPs for the LIST. (It's usually
+   convenient to also allocate a new Frame when you encounter FORM of
+   the right type.)
+
+   NEW is allocated by the caller but not initialized.  The caller
+   does not deallocate the context or access the parent context before
+   calling iff_close_read_group.
+
+   Returns a BAD_IFF error if the context's end is odd or extends past
+   the parent.  */
+static IFFP iff_open_read_group (iff_group_context *parent,
+				 iff_group_context *new);
+
+/* Close a group read context, updating its parent context.  After
+   calling this, the old context may be deallocated and the parent
+   context can be accessed again. It's okay to call this particular
+   procedure after an error has occurred reading the group.  This
+   always returns IFF_OKAY.  */
+static IFFP iff_close_read_group (iff_group_context *old);
+
+/* Skip any remaining bytes of the previous chunk and any padding,
+   then read the next chunk header into context.ck_hdr.
+
+   If the chunk ID is LIST, FORM, CAT, or PROP, this automatically
+   reads the subtype ID into context->subtype.  Caller should dispatch
+   on the chunk's ID (and subtype) to an appropriate handler.
+
+   Returns context.ck_hdr.ID (the ID of the new chunk header); END_MARK
+   if there are no more chunks in this context; NOT_IFF if the top
+   level file chunk isn't a FORM, LIST, or CAT; or BAD_IFF if
+   malformed chunk, e.g., chunk's size is negative or too big for
+   containing context, chunk ID isn't positive, or we hit end-of-file.
+
+   See also iff_get_form_chunk_header, below.  */
+
+static ID iff_get_chunk_header (iff_group_context *ctx);
+
+/* Read NBYTES number of data bytes of current chunk into BUFFER.
+   (Use OpenGroup, etc.  instead to read the contents of a group
+   chunk.)  You can call this several times to read the data
+   piecemeal.
+
+   Returns CLIENT_ERROR if NBYTES < 0.  SHORT_CHUNK if NBYTES >
+   CHUNK_MORE_BYTES(context) which could be due to a client bug or a
+   chunk that's shorter than it ought to be (bad form).  On either
+   CLIENT_ERROR or SHORT_CHUNK, iff_read_bytes won't read any bytes.  */
+
+static IFFP iff_read_bytes (iff_group_context *ctx,
+			    bfd_byte *buffer, int nbytes);
+
+/* IFF File Reader.  */
+
+/* This is a noop iff_group_client_proc that you can use for a
+   get_list, get_form, get_prop, or get_cat procedure that just skips
+   the group.  A simple reader might just implement get_form, store
+   &iff_read_cat in the get_cat field of client_frame, and use
+   &iff_skip_group for the get_list and get_prop procs.  */
+
+static IFFP iff_skip_group (iff_group_context *);
+
+/* IFF file reader.
+
+   Given an open file, allocate a group context and use it to read the
+   FORM, LIST, or CAT and it's contents. The idea is to parse the
+   file's contents, and for each FORM, LIST, CAT, or PROP encountered,
+   call the get_form, get_list, get_cat, or get_prop procedure in
+   client_frame, passing the iff_group_context ptr.
+
+   This is achieved with the aid of iff_read_list (which your get_list
+   should call) and iff_read_cat (which your get_cat should call, if you
+   don't just use &iff_read_cat for your get_cat). If you want to handle
+   FORMs, LISTs, and CATs nested within FORMs, the get_form procedure
+   must dispatch to get_form, get_list, and get_cat.
+
+   Normal return is IFF_OKAY (if whole file scanned) or IFF_DONE (if a
+   client proc said "done" first).
+
+   See the skeletal get_list, get_form, get_cat, and get_prop
+   procedures.  */
+static IFFP iff_read (bfd *file, iff_client_frame *client_frame);
+
+/* IFF LIST reader.
+
+   Your "get_list" procedure should allocate a iff_client_frame, copy the
+   parent's iff_client_frame, and then call this procedure to do all the
+   work.
+
+   Normal return is IFF_OKAY (if whole LIST scanned) or IFF_DONE (if a
+   client proc said "done" first).
+
+   Returns BAD_IFF error if a PROP appears after a non-PROP.  */
+static IFFP iff_read_list (iff_group_context *parent,
+			   iff_client_frame *client_frame);
+
+#if 0
+/* IFF CAT reader.  Most clients can simply use this to read their
+   CATs. If you must do extra setup work, put a ptr to your get_cat
+   procedure in the client_frame, and have that procedure call iff_read_cat
+   to do the detail work.
+
+   Normal return is IFF_OKAY (if whole CAT scanned) or IFF_DONE (if a
+   client proc said "done" first).
+
+   Returns BAD_IFF error if a PROP appears in the CAT.  */
+static IFFP iff_read_cat (iff_group_context *parent);
+#endif
+
+/* Call iff_get_form_chunk_header instead of iff_get_chunk_header to
+   read each chunk inside a FORM.  It just calls iff_get_chunk_header
+   and returns BAD_IFF if it gets a PROP chunk.  */
+static ID iff_get_form_chunk_header (iff_group_context *ctx);
+
+/* The following code is based on IFFR.C from the public domain IFF
+   reader.  Its header contains:  */
+
+/*--- begin original header --- */
+
+/*----------------------------------------------------------------------*
+ * IFFR.C  Support routines for reading IFF-85 files.          11/15/85
+ * (IFF is Interchange Format File.)
+ *
+ * By Jerry Morrison and Steve Shaw, Electronic Arts.
+ * This software is in the public domain.
+ *
+ * This version for the Commodore-Amiga computer.
+ *----------------------------------------------------------------------*/
+
+/*--- end original header --- */
+
+static IFFP
+iff_open_read (bfd *abfd, iff_group_context *new_ctx,
+	       iff_client_frame *client_frame)
+{
+  IFFP iffp = IFF_OKAY;
+
+  /* The "whole file" has no parent.  */
+  new_ctx->parent = NULL;
+  new_ctx->client_frame = client_frame;
+  new_ctx->abfd = abfd;
+  new_ctx->position = 0;
+  new_ctx->ck_hdr.ID = new_ctx->subtype = NULL_CHUNK;
+  new_ctx->ck_hdr.size = new_ctx->bytesSoFar = 0;
+
+  /* Set new_ctx->bound.  */
+  if (abfd == NULL)
+    return NO_FILE;
+  new_ctx->bound = bfd_get_size (abfd);
+  if (new_ctx->bound < 0)
+    return OS_ERROR;
+
+  if (new_ctx->bound < (long) sizeof (iff_chunk_header))
+    iffp = NOT_IFF;
+
+  return iffp;
+}
+
+static IFFP
+iff_open_read_group (iff_group_context* parent, iff_group_context* new_ctx)
+{
+  IFFP iffp = IFF_OKAY;
+
+  new_ctx->parent = parent;
+  new_ctx->client_frame = parent->client_frame;
+  new_ctx->abfd = parent->abfd;
+  new_ctx->position = parent->position;
+  new_ctx->bound = parent->position + CHUNK_MORE_BYTES (parent);
+  new_ctx->ck_hdr.ID = new_ctx->subtype = NULL_CHUNK;
+  new_ctx->ck_hdr.size = new_ctx->bytesSoFar = 0;
+
+  if (new_ctx->bound > parent->bound || IS_ODD (new_ctx->bound))
+    iffp = BAD_IFF;
+
+  return iffp;
+}
+
+static IFFP
+iff_close_read_group (iff_group_context *context)
+{
+  if (context->parent == NULL)
+    {
+       /* Context for whole file.  */
+    }
+  else
+    {
+      int position;
+
+      position = context->position;
+      context->parent->bytesSoFar += position - context->parent->position;
+      context->parent->position = position;
+    }
+
+  return IFF_OKAY;
+}
+
+/* Skip over bytes in a context. Won't go backwards.  Updates
+   context->position but not context->bytesSoFar.  */
+
+static IFFP
+skip_fwd (iff_group_context *context, int bytes)
+{
+  IFFP iffp = IFF_OKAY;
+
+  if (bytes > 0)
+    {
+      if (-1 == bfd_seek (context->abfd, bytes, SEEK_CUR))
+	iffp = BAD_IFF;   /* Ran out of bytes before chunk
+			     complete.  */
+      else
+	context->position += bytes;
+    }
+
+  return iffp;
+}
+
+static IFFP
+iff_get_chunk_header (iff_group_context *context)
+{
+  IFFP iffp;
+  int remaining;
+
+  /* Skip remainder of previous chunk & padding. */
+  iffp = skip_fwd (context,
+		   CHUNK_MORE_BYTES (context) + IS_ODD (context->ck_hdr.size));
+  if (iffp != IFF_OKAY)
+    return iffp;
+
+  /* Set up to read the newtmp header.  Until we know it's okay, mark
+     it BAD.  */
+  context->ck_hdr.ID = BAD_IFF;
+  context->subtype = NULL_CHUNK;
+  context->bytesSoFar = 0;
+
+  /* Generate a pseudo-chunk if at end-of-context.  */
+  remaining = context->bound - context->position;
+  if (remaining == 0 )
+    {
+      context->ck_hdr.size = 0;
+      context->ck_hdr.ID = END_MARK;
+    }
+  else if ((long) sizeof (iff_chunk_header) > remaining)
+    {
+      /* BAD_IFF if not enough bytes in the context for a
+	 iff_chunk_header.  */
+      context->ck_hdr.size = remaining;
+    }
+  else
+    {
+      /* Read the chunk header (finally).  */
+
+      /* All chunks start with a type ID and a count of the data bytes
+	 that follow--the chunk's "logical size" or "data size".  If
+	 that number is odd, a 0 pad byte is written, too.  */
+      char buf[8];
+
+      switch (bfd_bread (buf, 8, context->abfd))
+	{
+	case -1:
+	  return (context->ck_hdr.ID = OS_ERROR);
+	case 0:
+	  return (context->ck_hdr.ID = BAD_IFF);
+	}
+
+      context->ck_hdr.ID = bfd_getb32 (buf);
+      context->ck_hdr.size = bfd_getb32 (buf + 4);
+
+      /* Check: Top level chunk must be LIST or FORM or CAT.  */
+      if (context->parent == NULL
+	  && context->ck_hdr.ID != FORM
+	  && context->ck_hdr.ID != LIST
+	  && context->ck_hdr.ID != CAT)
+	return (context->ck_hdr.ID = NOT_IFF);
+
+      /* Update the context. */
+      context->position += (long) sizeof (iff_chunk_header);
+      remaining -= (long) sizeof (iff_chunk_header);
+
+      if (context->ck_hdr.ID <= 0)
+	{
+	  /* Non-positive int values are illegal and used for error
+	     codes.  We could check for other illegal IDs...  */
+	  context->ck_hdr.ID = BAD_IFF;
+	}
+      else if (context->ck_hdr.size < 0
+	       || context->ck_hdr.size > remaining)
+	{
+	  /* Check: size negative or larger than the number of bytes
+	     left in context?  */
+	  context->ck_hdr.size = remaining;
+	  context->ck_hdr.ID = BAD_IFF;
+	}
+    else
+      {
+	/* Automatically read the LIST, FORM, PROP, or CAT subtype
+	   int.  */
+	if (context->ck_hdr.ID == LIST
+	    || context->ck_hdr.ID == FORM
+	    || context->ck_hdr.ID == PROP
+	    || context->ck_hdr.ID == CAT)
+	  {
+	    uint32_t id;
+
+	    iffp = iff_read_bytes (context, (bfd_byte *) &id, 4);
+
+	    if (iffp != IFF_OKAY)
+	      context->ck_hdr.ID = iffp;
+	    else
+	      context->subtype = bfd_getb32 (&id);
+	  }
+      }
+  }
+
+  return context->ck_hdr.ID;
+}
+
+static IFFP
+iff_read_bytes (iff_group_context *context, bfd_byte *buffer, int nbytes)
+{
+  IFFP iffp = IFF_OKAY;
+
+  if (nbytes < 0)
+    iffp = CLIENT_ERROR;
+  else if (nbytes > CHUNK_MORE_BYTES (context))
+    iffp = SHORT_CHUNK;
+  else if (nbytes > 0)
+    {
+      switch (bfd_bread (buffer, nbytes, context->abfd))
+	{
+	case -1:
+	  iffp = OS_ERROR;
+	  break;
+	case 0:
+	  iffp = BAD_IFF;
+	  break;
+	default:
+	  context->position += nbytes;
+	  context->bytesSoFar += nbytes;
+	  break;
+	}
+    }
+
+  return iffp;
+}
+
+static IFFP
+iff_skip_group (iff_group_context* context ATTRIBUTE_UNUSED)
+{
+  /* Nothing to do, thanks to iff_get_chunk_header.  */
+  return 0;
+}
+
+static IFFP
+iff_read (bfd *file, iff_client_frame *client_frame)
+{
+  IFFP iffp;
+  iff_group_context context;
+
+  iffp = iff_open_read (file, &context, client_frame);
+  context.client_frame = client_frame;
+
+  if (iffp == IFF_OKAY)
+    {
+      iffp = iff_get_chunk_header (&context);
+
+      if (iffp == FORM)
+	iffp = (*client_frame->get_form) (&context);
+      else if (iffp == LIST)
+	iffp = (*client_frame->get_list) (&context);
+      else if (iffp == CAT)
+	iffp = (*client_frame->get_cat) (&context);
+    }
+  iff_close_read_group (&context);
+
+  if (iffp > 0)
+    iffp = NOT_IFF; /* iff_get_chunk_header should've caught this.  */
+  return iffp;
+}
+
+static IFFP
+iff_read_list (iff_group_context *parent, iff_client_frame *client_frame)
+{
+  iff_group_context list_context;
+  IFFP iffp;
+  bfd_boolean prop_ok = TRUE;
+
+  iffp = iff_open_read_group (parent, &list_context);
+  if (iffp != IFF_OKAY)
+    return iffp;
+
+  /* One special case test lets us handle CATs as well as LISTs.  */
+  if (parent->ck_hdr.ID == CAT)
+    prop_ok = FALSE;
+  else
+    list_context.client_frame = client_frame;
+
+  do
+    {
+      iffp = iff_get_chunk_header (&list_context);
+      if (iffp == PROP)
+	{
+	  if (prop_ok)
+	    iffp = (*client_frame->get_prop) (&list_context);
+	  else
+	    iffp = BAD_IFF;
+	}
+      else if (iffp == FORM)
+	iffp = (*client_frame->get_form) (&list_context);
+      else if (iffp == LIST)
+	iffp = (*client_frame->get_list) (&list_context);
+      else if (iffp == CAT)
+	iffp = (*client_frame->get_cat) (&list_context);
+
+      if (list_context.ck_hdr.ID != PROP)
+	prop_ok = FALSE;   /* No PROPs allowed after this point.  */
+  } while (iffp == IFF_OKAY);
+
+  iff_close_read_group (&list_context);
+
+  /* Only chunk types above are allowed in a LIST/CAT.  */
+  if (iffp > 0)
+    iffp = BAD_IFF;
+  return (iffp == END_MARK ? IFF_OKAY : iffp);
+}
+
+#if 0
+/* By special arrangement with the iff_read_list implementation, this
+   is trivial.  */
+
+static IFFP
+iff_read_cat (iff_group_context *parent)
+{
+  return iff_read_list (parent, parent->client_frame);
+}
+#endif
+
+static int
+iff_get_form_chunk_header (iff_group_context *context)
+{
+  int id;
+
+  id = iff_get_chunk_header (context);
+  if (id == PROP)
+    context->ck_hdr.ID = id = BAD_IFF;
+  return id;
+}
+
+/* End of generic IFF reader.  */
+

+
+/* PMD reader. */
+
+typedef uint32_t U32;
+
+#define MONITOR_INTERFACE_REQUEST 39000
+#define MONITOR_CONNECT_REQUEST 39008
+#define MONITOR_GET_PROCESS_INFO_REQUEST 39010
+#define MONITOR_GET_PROCESS_INFO_REPLY 39011
+#define MONITOR_GET_BLOCK_INFO_REQUEST 39014
+#define MONITOR_GET_SEGMENT_INFO_REQUEST 39017
+#define MONITOR_GET_REGISTER_INFO_REQUEST 39121
+#define MONITOR_GET_REGISTERS_REPLY 39106
+
+#define MONITOR_GET_TRACE_REQUEST 39215
+
+#define PM_PROGRAMS_REQUEST 36232
+#define PM_PROGRAM_INFO_REQUEST 36234
+#define PM_LOAD_MODULE_INSTALL_HANDLES_REQUEST 36214
+#define PM_LOAD_MODULE_INFO_REQUEST 36216
+#define PM_LOAD_MODULE_SECTION_INFO_REQUEST 36218
+#define PM_LOAD_MODULE_SECTION_INFO_REPLY 36219
+
+typedef uint32_t MonitorScopeType;
+
+typedef struct MonitorScope
+{
+   MonitorScopeType type;
+   uint32_t id;
+} MonitorScope;
+
+typedef uint32_t MonitorRegisterId;
+
+typedef struct MonitorGetRegisterInfoRequest
+{
+   uint32_t sigNo;
+   uint32_t reserved0;
+   MonitorScope scope;
+   uint32_t reserved1;
+   uint32_t registersCount;
+   MonitorRegisterId registers[1];
+} MonitorGetRegisterInfoRequest;
+
+typedef uint32_t MonitorStatus;
+
+typedef struct MonitorRegister
+{
+   MonitorRegisterId id;
+   uint32_t value;
+} MonitorRegister;
+
+typedef struct MonitorRegisterValues
+{
+   uint32_t sigNo;
+   uint32_t pid;
+   MonitorStatus status;
+   uint32_t registersCount;
+   MonitorRegister registers[1];
+} MonitorRegisterValues;
+
+typedef uint32_t MonitorProcessType;
+typedef uint32_t MonitorProcessState;
+
+typedef struct MonitorGetProcessInfoReply
+{
+   uint32_t sigNo;
+   uint32_t pid;
+   uint32_t bid;
+   uint32_t sid;
+   MonitorProcessType type;
+   MonitorProcessState state;
+   uint32_t priority;
+   uint32_t entrypoint;
+   uint32_t properties;
+   uint32_t reserved1;
+   char name[1];
+} MonitorGetProcessInfoReply;
+
+#define MONITOR_REGISTER_INVALID 0x80000000
+
+#define MONITOR_REGISTER_IS_INVALID(MONITOR_REGISTER) \
+   (((MONITOR_REGISTER) & MONITOR_REGISTER_INVALID) >> 31)
+
+static const char *
+ose_signal_to_str (int sig)
+{
+  static char buffer[512];
+
+#define SIGNAL(SIG) case SIG:				\
+  sprintf (buffer, "%s: 0x%x (%d)", #SIG, SIG, SIG);	\
+  break
+
+  switch (sig)
+    {
+      SIGNAL (MONITOR_INTERFACE_REQUEST);
+      SIGNAL (MONITOR_CONNECT_REQUEST);
+      SIGNAL (MONITOR_GET_PROCESS_INFO_REQUEST);
+      SIGNAL (MONITOR_GET_BLOCK_INFO_REQUEST);
+      SIGNAL (MONITOR_GET_SEGMENT_INFO_REQUEST);
+      SIGNAL (MONITOR_GET_REGISTER_INFO_REQUEST);
+
+      SIGNAL (MONITOR_GET_TRACE_REQUEST);
+
+      SIGNAL (PM_PROGRAMS_REQUEST);
+      SIGNAL (PM_PROGRAM_INFO_REQUEST);
+      SIGNAL (PM_LOAD_MODULE_INSTALL_HANDLES_REQUEST);
+      SIGNAL (PM_LOAD_MODULE_INFO_REQUEST);
+      SIGNAL (PM_LOAD_MODULE_SECTION_INFO_REQUEST);
+    default:
+      sprintf (buffer, "unknown OSE signal 0x%x (%d)", sig, sig);
+      break;
+    }
+
+  return buffer;
+}
+
+/* RAM Dump File format grammar:
+
+   Chunk ::= ID Size U32*
+   GroupChunk ::= ID Size SubID (Chunk | GroupChunk)*
+   ID ::= U32
+   Size ::= BigEndianU32
+
+   Dump ::= 'FORM' Size 'PMD ' (Vers | DumpId | BlockList)*
+   Vers ::= 'VERS' Size(4) U32(<version>)
+   DumpId ::= 'DPID' Size(4) U32(<dump id>)
+   BlockList ::= 'LIST' Size 'BLOC' (BlockForm)*
+   BlockForm ::= 'FORM' Size 'BLOC' (BlockChunk)*
+   BlockChunk ::= BlockHead | ErrorForm | TextForm | MemoryForm
+   BlockHead ::= 'BLHD' Size(16) U32(<dump id>) U32(<block no>)
+		  U32(<seconds since Jan 1 1970, 00:00>)
+		  U32(<additional microseconds>)
+   ErrorForm ::= 'FORM' Size 'ERBL' (Descr | ErrInfo)*
+		Descr ::= 'DESC' Size(<size of text>) <text>
+		ErrInfo ::= 'ERIN' Size(16) U32(<user_called>) U32(<error_code>)
+		U32(<extra>) U32(<curr_proc>)
+   TextForm ::= 'FORM' Size 'TXBL' (Descr)*
+   MemoryForm ::= 'FORM' Size 'MBL ' (Descr | (MemDef (Data | Zdata)))*
+   MemDef ::= 'MHD' Size(8) U32(<start>) U32(<length>)
+   Data ::= 'DATA' Size(<length of data>) <data>
+   Zdata ::= 'FORM' Size 'ZDAT' Zdef Data
+   Zdef ::= 'ZDEF' Size U32(<method>) U32[4](<parameters>)
+	    U32(<image_length>) U32(<reserved>)
+*/
+
+/* IDs for the above grammar.  */
+
+#define ID_PMD MakeID ('P','M','D',' ')
+#define ID_VERS MakeID ('V','E','R','S')
+#define ID_DPID MakeID ('D','P','I','D')
+#define ID_BLOC MakeID ('B','L','O','C')
+#define ID_BLHD MakeID ('B','L','H','D')
+#define ID_ERBL MakeID ('E','R','B','L')
+#define ID_TXBL MakeID ('T','X','B','L')
+#define ID_MBL MakeID ('M','B','L',' ')
+#define ID_SGBL MakeID ('S','G','B','L')
+#define ID_SGHD MakeID ('S','G','H','D')
+#define ID_DATA MakeID ('D','A','T','A')
+#define ID_ZDAT MakeID ('Z','D','A','T')
+#define ID_DESC MakeID ('D','E','S','C')
+#define ID_ERIN MakeID ('E','R','I','N')
+#define ID_MHD MakeID ('M','H','D',' ')
+#define ID_ZDEF MakeID ('Z','D','E','F')
+
+/* FIXME: should not be a global.  */
+int last_data_section;
+
+/* We don't parse any properties, so we don't need to extend the
+   client frame.  */
+typedef struct pmd_frame
+{
+  iff_client_frame client_frame;
+} pmd_frame;
+
+static IFFP
+read_U32 (iff_group_context *ctx, U32 *u32p)
+{
+  IFFP iffp = iff_read_bytes (ctx, (bfd_byte *) u32p, sizeof (U32));
+  *u32p = bfd_get_32 (ctx->abfd, u32p);
+  return iffp;
+}
+
+static bfd_byte *
+get_U32 (iff_group_context *ctx, bfd_byte *p, U32 *u32p)
+{
+  memcpy (u32p, p, 4);
+  p += 4;
+  *u32p = bfd_get_32 (ctx->abfd, u32p);
+  return p;
+}
+
+static IFFP
+get_Descr (iff_group_context *ctx, char **desc)
+{
+  IFFP iffp;
+  int size_of_text = ctx->ck_hdr.size;
+  char *buf = bfd_malloc (size_of_text + 1);
+
+  iffp = iff_read_bytes (ctx, (bfd_byte *) buf, size_of_text);
+
+  if (iffp == IFF_OKAY)
+    {
+      buf[size_of_text] = 0;
+      *desc = buf;
+    }
+  else
+    {
+      free (buf);
+      *desc = NULL;
+    }
+
+  return iffp;
+}
+
+static IFFP
+get_ErrorForm (iff_group_context *parent)
+{
+  IFFP iffp;
+  iff_group_context form_context;
+  pmd_frame new_frame;
+
+  ose_debug ("Got ErrorForm\n");
+
+  new_frame = *(pmd_frame *) parent->client_frame;
+
+  new_frame.client_frame.get_list = iff_skip_group;
+  new_frame.client_frame.get_prop = iff_skip_group;
+  new_frame.client_frame.get_form = iff_skip_group;
+  new_frame.client_frame.get_cat = iff_skip_group;
+
+  iffp = iff_open_read_group (parent, &form_context);
+  if (iffp != IFF_OKAY)
+    return iffp;
+  form_context.client_frame = &new_frame.client_frame;
+
+  do
+    {
+      iffp = iff_get_form_chunk_header (&form_context);
+      if (iffp == ID_DESC)
+	{
+	  char *desc;
+
+	  iffp = get_Descr (&form_context, &desc);
+	  if (iffp == IFF_OKAY)
+	    {
+	      ose_debug ("ErrorForm description = %s\n", desc);
+	      free (desc);
+	    }
+	}
+      else if (iffp == ID_ERIN)
+	{
+	  U32 user_called, error_code, extra, curr_proc;
+
+	  iffp = read_U32 (&form_context, &user_called);
+	  iffp = read_U32 (&form_context, &error_code);
+	  iffp = read_U32 (&form_context, &extra);
+	  iffp = read_U32 (&form_context, &curr_proc);
+
+	  if (iffp == IFF_OKAY)
+	    {
+	      ose_debug ("user_called = 0x%x\n", user_called);
+	      ose_debug ("error_code = 0x%x\n", error_code);
+	      ose_debug ("extra = 0x%x\n", extra);
+	      ose_debug ("curr_proc = 0x%x\n", curr_proc);
+	    }
+	}
+    } while (iffp >= IFF_OKAY);
+
+  iff_close_read_group (&form_context);
+  return(iffp == END_MARK ? IFF_OKAY : iffp);
+}
+
+static IFFP
+get_TextForm (iff_group_context *parent)
+{
+  IFFP iffp;
+  iff_group_context form_context;
+  pmd_frame new_frame;
+
+  ose_debug ("Got TextForm\n");
+
+  new_frame = *(pmd_frame *) parent->client_frame;
+
+  new_frame.client_frame.get_list = iff_skip_group;
+  new_frame.client_frame.get_prop = iff_skip_group;
+  new_frame.client_frame.get_form = iff_skip_group;
+  new_frame.client_frame.get_cat = iff_skip_group;
+
+  iffp = iff_open_read_group (parent, &form_context);
+  if (iffp != IFF_OKAY)
+    return iffp;
+  form_context.client_frame = &new_frame.client_frame;
+
+  do
+    {
+      iffp = iff_get_form_chunk_header (&form_context);
+      if (iffp == ID_DESC)
+	{
+	  char *desc;
+
+	  iffp = get_Descr (&form_context, &desc);
+	  if (iffp == IFF_OKAY)
+	    {
+	      ose_debug ("TextForm description = %s\n", desc);
+	      free (desc);
+	    }
+	}
+      else if (iffp == ID_ERIN)
+	{
+	  U32 user_called, error_code, extra, curr_proc;
+
+	  iffp = read_U32 (&form_context, &user_called);
+	  iffp = read_U32 (&form_context, &error_code);
+	  iffp = read_U32 (&form_context, &extra);
+	  iffp = read_U32 (&form_context, &curr_proc);
+
+	  if (iffp == IFF_OKAY)
+	    {
+	      ose_debug ("user_called = 0x%x\n", user_called);
+	      ose_debug ("error_code = 0x%x\n", error_code);
+	      ose_debug ("extra = 0x%x\n", extra);
+	      ose_debug ("curr_proc = 0x%x\n", curr_proc);
+	    }
+	}
+    } while (iffp >= IFF_OKAY);
+
+  iff_close_read_group (&form_context);
+  return(iffp == END_MARK ? IFF_OKAY : iffp);
+}
+
+static IFFP
+get_MemDef (iff_group_context *ctx, U32 *start, U32 *length)
+{
+  IFFP iffp;
+
+  iffp = read_U32 (ctx, start);
+  iffp = read_U32 (ctx, length);
+
+  return iffp;
+}
+
+static bfd_byte *get_DataOrZdat (iff_group_context *ctx, bfd_byte *buf,
+				 size_t length);
+
+static IFFP
+get_MemoryForm (iff_group_context *parent)
+{
+  IFFP iffp;
+  iff_group_context form_context;
+  pmd_frame new_frame;
+
+  ose_debug ("Got MemoryForm\n");
+
+  new_frame = *(pmd_frame *) parent->client_frame;
+
+  new_frame.client_frame.get_list = iff_skip_group;
+  new_frame.client_frame.get_prop = iff_skip_group;
+  new_frame.client_frame.get_form = iff_skip_group;
+  new_frame.client_frame.get_cat = iff_skip_group;
+
+  iffp = iff_open_read_group (parent, &form_context);
+  if (iffp != IFF_OKAY)
+    return iffp;
+  form_context.client_frame = &new_frame.client_frame;
+
+  do
+    {
+      iffp = iff_get_form_chunk_header (&form_context);
+      if (iffp == ID_DESC)
+	{
+	  char *desc;
+
+	  iffp = get_Descr (&form_context, &desc);
+	  if (iffp == IFF_OKAY)
+	    {
+	      ose_debug ("TextForm description = %s\n", desc);
+	      free (desc);
+	    }
+	}
+      else if (iffp == ID_MHD)
+	{
+	  U32 start, length;
+
+	  iffp = get_MemDef (&form_context, &start, &length);
+
+	  if (iffp == IFF_OKAY)
+	    {
+	      bfd_byte *data, *mem;
+
+	      ose_debug ("start = 0x%x\n", start);
+	      ose_debug ("length = 0x%x\n", length);
+
+	      data = bfd_malloc (length);
+
+	      mem = get_DataOrZdat (&form_context, data, length);
+
+	      if (mem != NULL)
+		{
+		  flagword flags;
+		  asection *asect;
+		  char buf[100];
+		  bfd *abfd = form_context.abfd;
+		  size_t len;
+		  char *sect_name;
+
+		  sprintf (buf, "mem%d", last_data_section);
+
+		  /* Build the section name.  */
+
+		  len = strlen (buf) + 1;
+		  sect_name = (char *) bfd_alloc (abfd, len);
+		  if (sect_name == NULL)
+		    ;
+		  else
+		    {
+		      memcpy (sect_name, buf, len);
+
+		      flags = (SEC_ALLOC | SEC_LOAD
+			       | SEC_HAS_CONTENTS | SEC_IN_MEMORY);
+		      asect = bfd_make_section_anyway_with_flags (abfd,
+								  sect_name,
+								  flags);
+		      if (asect == NULL)
+			{
+			  /* warn? */
+			}
+		      else
+			{
+			  asect->size = length;
+			  asect->vma = start;
+			  asect->filepos = 0;
+			  asect->contents = mem;
+
+			  last_data_section++;
+			}
+		    }
+		}
+
+	      free (data);
+	    }
+	}
+    } while (iffp >= IFF_OKAY);
+
+  iff_close_read_group (&form_context);
+  return(iffp == END_MARK ? IFF_OKAY : iffp);
+}
+
+/* Decompress a chunk that was compressed using zlib.  */
+
+#ifdef HAVE_ZLIB_H
+
+static bfd_boolean
+zlib_inflate_buffer (bfd_byte *compressed_buffer,
+		     size_t compressed_size,
+		     bfd_byte *uncompressed_buffer,
+		     bfd_size_type uncompressed_size)
+{
+  z_stream strm;
+  int rc;
+
+  strm.zalloc = NULL;
+  strm.zfree = NULL;
+  strm.opaque = NULL;
+  strm.avail_in = compressed_size;
+  strm.next_in = (Bytef *) compressed_buffer;
+  strm.avail_out = uncompressed_size;
+
+  rc = inflateInit (&strm);
+  while (strm.avail_in > 0)
+    {
+      if (rc != Z_OK)
+	return FALSE;
+      strm.next_out = ((Bytef *) uncompressed_buffer
+		       + (uncompressed_size - strm.avail_out));
+      rc = inflate (&strm, Z_FINISH);
+      if (rc != Z_STREAM_END)
+	return FALSE;
+      rc = inflateReset (&strm);
+    }
+  rc = inflateEnd (&strm);
+  if (rc != Z_OK
+      || strm.avail_out != 0)
+    return FALSE;
+
+  return TRUE;
+}
+
+#endif
+
+#define RAMDUMP_COMPRESS_ZLIB_Z77   ((U32) 0x1)
+
+static IFFP
+get_Zdata (iff_group_context *parent, bfd_byte *buf, size_t length)
+{
+  IFFP iffp;
+  iff_group_context form_context;
+  pmd_frame new_frame;
+
+  /* Just ignore unknown forms.  */
+  if (parent->subtype != ID_ZDAT)
+    return IFF_OKAY;
+
+  new_frame = *(pmd_frame *) parent->client_frame;
+
+  new_frame.client_frame.get_list = iff_skip_group;
+  new_frame.client_frame.get_prop = iff_skip_group;
+  new_frame.client_frame.get_form = iff_skip_group;
+  new_frame.client_frame.get_cat = iff_skip_group;
+
+  iffp = iff_open_read_group (parent, &form_context);
+  if (iffp != IFF_OKAY)
+    return iffp;
+  form_context.client_frame = &new_frame.client_frame;
+
+  iffp = iff_get_form_chunk_header (&form_context);
+
+  if (iffp == ID_ZDEF)
+    {
+      U32 method;
+      U32 parameters[4];
+      U32 image_length;
+      U32 reserved;
+
+      bfd_byte *compressed;
+      int i;
+
+      iffp = read_U32 (&form_context, &method);
+      for (i = 0; i < 4; i++)
+	iffp = read_U32 (&form_context, &parameters[i]);
+      iffp = read_U32 (&form_context, &image_length);
+      iffp = read_U32 (&form_context, &reserved);
+
+      if (method == RAMDUMP_COMPRESS_ZLIB_Z77)
+	{
+	  iffp = iff_get_form_chunk_header (&form_context);
+
+	  if (iffp == ID_DATA)
+	    {
+	      /* FIXME: we could get away with this bfd_malloc.  */
+	      compressed = bfd_malloc (image_length);
+	      iffp = iff_read_bytes (&form_context, compressed, image_length);
+
+#ifdef HAVE_ZLIB_H
+	      if (!zlib_inflate_buffer (compressed, image_length,
+					buf, length))
+		iffp = BAD_IFF;
+	      else
+#endif
+		iffp = END_MARK;
+	    }
+	  else
+	    (*_bfd_error_handler)
+	      (_("warning: missing DATA chunk"));
+	}
+      else
+	{
+	  (*_bfd_error_handler)
+	    (_("warning: unsupported compression method: %d"), method);
+	}
+    }
+  else
+    {
+      (*_bfd_error_handler)
+	(_("warning: missing zdef"));
+    }
+
+  iff_close_read_group (&form_context);
+  return (iffp == END_MARK ? IFF_OKAY : iffp);
+}
+
+static bfd_byte *
+get_DataOrZdat (iff_group_context *ctx, bfd_byte *buf, size_t length)
+{
+  IFFP iffp;
+
+  iffp = iff_get_form_chunk_header (ctx);
+
+  if (iffp == ID_DATA)
+    {
+      iffp = iff_read_bytes (ctx, buf, length);
+      return buf;
+    }
+  else if (iffp == FORM && ctx->subtype == ID_ZDAT)
+    {
+      iffp = get_Zdata (ctx, buf, length);
+      return buf;
+    }
+  else
+    return NULL;
+}
+
+static void
+swap_in_MonitorGetRegisterInfoRequest (bfd *abfd,
+				       MonitorGetRegisterInfoRequest *sig)
+{
+  uint32_t i;
+
+  sig->sigNo = bfd_get_32 (abfd, &sig->sigNo);
+  sig->reserved0 = bfd_get_32 (abfd, &sig->reserved0);
+  sig->scope.type = bfd_get_32 (abfd, &sig->scope.type);
+  sig->scope.id = bfd_get_32 (abfd, &sig->scope.id);
+  sig->reserved1 = bfd_get_32 (abfd, &sig->reserved1);
+  sig->registersCount = bfd_get_32 (abfd, &sig->registersCount);
+
+  for (i = 0; i < sig->registersCount; i++)
+    sig->registers[i] = bfd_get_32 (abfd, &sig->registers[i]);
+}
+
+static void
+swap_in_MonitorRegisterValues (bfd *abfd, MonitorRegisterValues *sig)
+{
+  uint32_t i;
+
+  sig->sigNo = bfd_get_32 (abfd, &sig->sigNo);
+  sig->pid = bfd_get_32 (abfd, &sig->pid);
+  sig->status = bfd_get_32 (abfd, &sig->status);
+  sig->registersCount = bfd_get_32 (abfd, &sig->registersCount);
+
+  for (i = 0; i < sig->registersCount; i++)
+    {
+      sig->registers[i].id = bfd_get_32 (abfd, &sig->registers[i].id);
+      // sig->registers[i].value = bfd_get_32 (abfd, &sig->registers[i].value);
+    }
+}
+
+static void
+swap_in_MonitorGetProcessInfoReply (bfd *abfd, MonitorGetProcessInfoReply *sig)
+{
+  sig->sigNo = bfd_get_32 (abfd, &sig->sigNo);
+  sig->pid = bfd_get_32 (abfd, &sig->pid);
+  sig->bid = bfd_get_32 (abfd, &sig->bid);
+  sig->sid = bfd_get_32 (abfd, &sig->sid);
+  sig->type = bfd_get_32 (abfd, &sig->type);
+  sig->state = bfd_get_32 (abfd, &sig->state);
+  sig->priority = bfd_get_32 (abfd, &sig->priority);
+  sig->entrypoint = bfd_get_32 (abfd, &sig->entrypoint);
+  sig->properties = bfd_get_32 (abfd, &sig->properties);
+  sig->reserved1 = bfd_get_32 (abfd, &sig->reserved1);
+}
+
+#define ose_core_tdata(bfd)			\
+  ((bfd) -> tdata.ose_core_data)
+
+/* If there isn't a section called NAME, make one, using data from
+   SECT.  Note, this function will generate a reference to NAME, so
+   you shouldn't deallocate or overwrite it.  */
+
+static bfd_boolean
+maybe_make_sect (bfd *abfd, char *name, asection *sect)
+{
+  asection *sect2;
+
+  if (bfd_get_section_by_name (abfd, name) != NULL)
+    return TRUE;
+
+  sect2 = bfd_make_section_with_flags (abfd, name, sect->flags);
+  if (sect2 == NULL)
+    return FALSE;
+
+  sect2->size = sect->size;
+  sect2->filepos = sect->filepos;
+  sect2->alignment_power = sect->alignment_power;
+  sect2->contents = bfd_malloc (sect->size);
+  memcpy (sect2->contents, sect->contents, sect->size);
+  return TRUE;
+}
+
+/* Create a pseudosection containing a copy of the buffer CONTENTS of
+   SIZE bytes.  This actually creates up to two pseudosections:
+
+   - A section named "NAME/PID".
+   - A section named NAME, unless such a section already exists.  GDB
+     uses this section to select the current thread.
+
+   Both pseudosections have identical contents.  */
+
+static bfd_boolean
+make_pseudosection (bfd *abfd, char *name, U32 pid,
+		    bfd_byte *contents, size_t size)
+{
+  char buf[100];
+  char *threaded_name;
+  size_t len;
+  asection *sect;
+
+  /* Build the section name.  */
+
+  sprintf (buf, "%s/%d", name, pid);
+  len = strlen (buf) + 1;
+  threaded_name = (char *) bfd_alloc (abfd, len);
+  if (threaded_name == NULL)
+    return FALSE;
+  memcpy (threaded_name, buf, len);
+
+  sect = bfd_make_section_anyway_with_flags (abfd, threaded_name,
+					     SEC_HAS_CONTENTS | SEC_IN_MEMORY);
+  if (sect == NULL)
+    return FALSE;
+  sect->size = size;
+  sect->filepos = 0;
+  sect->alignment_power = 2;
+  sect->contents = bfd_malloc (size);
+  memcpy (sect->contents, contents, size);
+
+  return maybe_make_sect (abfd, name, sect);
+}
+
+static asection *
+make_section_for_signal (bfd *abfd, const char *sect_name,
+			 bfd_byte *sig, size_t length)
+{
+  flagword flags;
+  asection *asect;
+  size_t len;
+  char *copy;
+
+  /* Build the section name.  */
+
+  len = strlen (sect_name) + 1;
+  copy = (char *) bfd_alloc (abfd, len);
+  if (copy == NULL)
+    return NULL;
+
+  memcpy (copy, sect_name, len);
+
+  flags = SEC_HAS_CONTENTS | SEC_IN_MEMORY;
+  asect = bfd_make_section_anyway_with_flags (abfd, copy, flags);
+  if (asect == NULL)
+    return NULL;
+
+  asect->size = length;
+  asect->vma = 0;
+  asect->filepos = 0;
+  asect->contents = bfd_malloc (length);
+  memcpy (asect->contents, sig, length);
+
+  return asect;
+}
+
+static IFFP
+get_SigDef (iff_group_context *ctx)
+{
+  IFFP iffp;
+  U32 signo, status, length;
+
+  /* Each signal chunk contains a compressed sequence of C structs
+     where each C struct corresponds to a signal in a
+     request/reply(/endmark) signal transaction.
+
+     For example, the CPU registers are stored in a signal chunk as a
+     signal transaction consisting of the following signals:
+
+     MONITOR_GET_REGISTERS_INFO_REQUEST (MonitorGetRegisterInfoRequest struct)
+     MONITOR_GET_REGISTERS_REPLY (MonitorRegisterValues struct)
+
+     The actual structs are laid out consecutively in the following
+     manner in the SignalForm->Zdata->Data chunk:
+
+     (U32(<sigsize>) U32(<signo>) U32(<data>) <padding>)*
+  */
+
+  iffp = iff_get_form_chunk_header (ctx);
+  if (iffp != ID_SGHD)
+    return iffp;
+
+  iffp = read_U32 (ctx, &signo);
+  iffp = read_U32 (ctx, &status);
+  iffp = read_U32 (ctx, &length);
+
+  if (iffp == IFF_OKAY)
+    {
+      bfd_byte *data;
+      bfd_byte *sig;
+
+      ose_debug ("signal = %s\n", ose_signal_to_str (signo));
+      ose_debug ("status = 0x%x (%d)\n", status, status);
+      ose_debug ("length = 0x%x (%d)\n", length, length);
+
+      data = bfd_malloc (length);
+
+      sig = get_DataOrZdat (ctx, data, length);
+      if (sig == NULL)
+	;
+      else
+	{
+	  bfd_byte *end = sig + length;
+
+	  while (sig < end)
+	    {
+	      U32 data_sigsize, data_signo;
+
+	      sig = get_U32 (ctx, sig, &data_sigsize);
+	      get_U32 (ctx, sig, &data_signo);
+
+	      ose_debug ("data signal = %s\n", ose_signal_to_str (data_signo));
+
+	      if (data_signo == MONITOR_GET_REGISTER_INFO_REQUEST)
+		{
+		  MonitorGetRegisterInfoRequest *req = (void *) sig;
+
+		  swap_in_MonitorGetRegisterInfoRequest (ctx->abfd, req);
+
+		  ose_debug ("length = 0x%x (%d)\n", length, length);
+		}
+	      else if (data_signo == MONITOR_GET_REGISTERS_REPLY)
+		{
+		  MonitorRegisterValues *reply = (void *) sig;
+		  bfd *abfd = ctx->abfd;
+
+		  swap_in_MonitorRegisterValues (ctx->abfd, reply);
+
+		  /* Sometimes OSE dumps two chunks containing
+		     registers.  The registers that are marked as
+		     valid in the second chunk should replace the
+		     corresponding registers in the first chunk.
+		     Don't ask...  */
+
+		  /* FIXME: we should be merging the registers sets,
+		     not just blindly taking the latter one.  */
+		  if (reply->registersCount > 0
+		      && !MONITOR_REGISTER_IS_INVALID (reply->registers[0].id))
+		    {
+		      /* Make a ".reg/999" section and a ".reg" section.  */
+		      make_pseudosection (abfd, ".reg", reply->pid,
+					  sig, data_sigsize);
+		      ose_debug ("found registers for pid=0x%x\n", reply->pid);
+		    }
+		  else
+		    ose_debug ("found invalid registers for pid=0x%x."
+			       "  ignoring\n", reply->pid);
+		}
+	      else if (data_signo == MONITOR_GET_PROCESS_INFO_REPLY)
+		{
+		  MonitorGetProcessInfoReply *reply = (void *) sig;
+
+		  swap_in_MonitorGetProcessInfoReply (ctx->abfd, reply);
+
+		  ose_debug ("found process = pid=0x%x,"
+			     "bid=0x%x,sid=0x%x,name=%s\n",
+			     reply->pid, reply->bid, reply->sid, reply->name);
+		}
+	      else if (data_signo == PM_LOAD_MODULE_SECTION_INFO_REPLY)
+		{
+		  asection *asect;
+		  bfd *abfd = ctx->abfd;
+
+		  asect = make_section_for_signal (abfd, ".section-info",
+						   sig, data_sigsize);
+		  if (asect == NULL)
+		    {
+		      /* warn? */
+		    }
+		}
+
+	      sig += data_sigsize;
+	      sig += (4 - (data_sigsize % 4)) % 4;
+	    }
+	}
+
+      free (data);
+    }
+
+  return iffp;
+}
+
+static IFFP
+get_SignalForm (iff_group_context *parent)
+{
+  IFFP iffp;
+  iff_group_context form_context;
+  pmd_frame new_frame;
+
+  /* Just ignore unknown forms.  */
+  if (parent->subtype != ID_SGBL)
+    return IFF_OKAY;
+
+  ose_debug ("Got SignalForm\n");
+
+  new_frame = *(pmd_frame *) parent->client_frame;
+
+  new_frame.client_frame.get_list = iff_skip_group;
+  new_frame.client_frame.get_prop = iff_skip_group;
+  new_frame.client_frame.get_form = iff_skip_group;
+  new_frame.client_frame.get_cat = iff_skip_group;
+
+  iffp = iff_open_read_group (parent, &form_context);
+  if (iffp != IFF_OKAY)
+    return iffp;
+  form_context.client_frame = &new_frame.client_frame;
+
+  do
+    {
+      iffp = get_SigDef (&form_context);
+    } while (iffp >= IFF_OKAY);
+
+  iff_close_read_group (&form_context);
+  return(iffp == END_MARK ? IFF_OKAY : iffp);
+}
+
+static IFFP
+get_BlockForm (iff_group_context *parent)
+{
+  IFFP iffp;
+  iff_group_context form_context;
+  pmd_frame new_frame;
+
+  /* Just ignore unknown forms.  */
+  if (parent->subtype != ID_BLOC)
+    return IFF_OKAY;
+
+  new_frame = *(pmd_frame *) parent->client_frame;
+
+  new_frame.client_frame.get_list = iff_skip_group;
+  new_frame.client_frame.get_prop = iff_skip_group;
+  new_frame.client_frame.get_form = get_SignalForm;
+  new_frame.client_frame.get_cat = iff_skip_group;
+
+  iffp = iff_open_read_group (parent, &form_context);
+  if (iffp != IFF_OKAY)
+    return iffp;
+  form_context.client_frame = &new_frame.client_frame;
+
+  do
+    {
+      iffp = iff_get_form_chunk_header (&form_context);
+      if (iffp == ID_BLHD)
+	{
+	  U32 dump_id, block_no, sepoc, us;
+
+	  iffp = read_U32 (&form_context, &dump_id);
+	  iffp = read_U32 (&form_context, &block_no);
+	  iffp = read_U32 (&form_context, &sepoc);
+	  iffp = read_U32 (&form_context, &us);
+
+	  if (iffp == IFF_OKAY)
+	    {
+	      ose_debug ("BLHD\n");
+	      ose_debug ("..dump id = %u\n", dump_id);
+	      ose_debug ("..block no = %u\n", block_no);
+	      ose_debug ("..seconds since epoc = %u\n", sepoc);
+	      ose_debug ("..additional microseconds = %u\n", us);
+	    }
+	}
+      else if (iffp == FORM && form_context.subtype == ID_ERBL)
+	{
+	  ose_debug ("Got ID_ERBL\n");
+	  iffp = get_ErrorForm (&form_context);
+	}
+      else if (iffp == FORM && form_context.subtype == ID_TXBL)
+	{
+	  ose_debug ("Got ID_TXBL\n");
+	  iffp = get_TextForm (&form_context);
+	}
+      else if (iffp == FORM && form_context.subtype == ID_MBL)
+	{
+	  ose_debug ("Got ID_MBL\n");
+	  iffp = get_MemoryForm (&form_context);
+	}
+      else if (iffp == FORM && form_context.subtype == ID_SGBL)
+	{
+	  iffp = get_SignalForm (&form_context);
+	}
+    } while (iffp >= IFF_OKAY);
+
+  iff_close_read_group (&form_context);
+  return(iffp == END_MARK ? IFF_OKAY : iffp);
+}
+
+static IFFP
+read_BlockList (iff_group_context *parent)
+{
+  pmd_frame new_frame;
+
+  new_frame = *(pmd_frame *) parent->client_frame;
+
+  new_frame.client_frame.get_list = iff_skip_group;
+  new_frame.client_frame.get_prop = iff_skip_group;
+  new_frame.client_frame.get_form = get_BlockForm;
+  new_frame.client_frame.get_cat = iff_skip_group;
+
+  return iff_read_list (parent, (iff_client_frame *) &new_frame);
+}
+
+static IFFP
+get_Dump (iff_group_context *parent)
+{
+  IFFP iffp;
+  iff_group_context form_context;
+  pmd_frame new_frame;
+  U32 version = 0;
+  U32 dump_id = 0;
+
+  /* Just ignore unknown forms.  */
+  if (parent->subtype != ID_PMD)
+    return IFF_OKAY;
+
+  new_frame = *(pmd_frame *) parent->client_frame;
+
+  new_frame.client_frame.get_list = iff_skip_group;
+  new_frame.client_frame.get_prop = iff_skip_group;
+  new_frame.client_frame.get_form = iff_skip_group;
+  new_frame.client_frame.get_cat = iff_skip_group;
+
+  iffp = iff_open_read_group (parent, &form_context);
+  if (iffp != IFF_OKAY)
+    return iffp;
+  form_context.client_frame = &new_frame.client_frame;
+
+  do
+    {
+      iffp = iff_get_form_chunk_header (&form_context);
+
+      if (iffp == LIST && form_context.subtype == ID_BLOC)
+	{
+	  iffp = read_BlockList (&form_context);
+	}
+      else if (iffp == ID_VERS)
+	{
+	  iffp = read_U32 (&form_context, &version);
+	  ose_debug ("version = %d\n", version);
+	}
+      else if (iffp == ID_DPID)
+	{
+	  iffp = read_U32 (&form_context, &dump_id);
+	  ose_debug ("dump id = %d\n", dump_id);
+	}
+      else if (iffp == END_MARK)
+	iffp = IFF_DONE;
+    } while (iffp >= IFF_OKAY);
+
+  if (iffp != IFF_DONE)
+    return iffp;
+
+  /* If we get this far, there were no errors.  */
+  iff_close_read_group (&form_context);
+  return iffp;
+}
+
+static IFFP
+read_pmd (bfd *file, pmd_frame *iFrame)
+{
+  iFrame->client_frame.get_list = iff_skip_group;
+  iFrame->client_frame.get_prop = iff_skip_group;
+  iFrame->client_frame.get_form = get_Dump;
+  iFrame->client_frame.get_cat = iff_skip_group;
+
+  return iff_read (file, (iff_client_frame *) iFrame);
+}
+
+

+
+#define ose_core_file_matches_executable_p \
+  generic_core_file_matches_executable_p
+
+static int
+ose_core_file_pid (bfd *abfd)
+{
+  return ose_core_tdata (abfd)->bid;
+}
+
+static const bfd_target *
+ose_core_file_p (bfd *abfd)
+{
+  bfd_size_type amt;
+  IFFP iffp;
+  pmd_frame iFrame;
+
+#ifndef HAVE_ZLIB_H
+  return NULL;
+#endif
+
+  iffp = read_pmd (abfd, &iFrame);
+  if (iffp == BAD_IFF || iffp == NOT_IFF)
+    return NULL;
+
+  if (iffp != IFF_DONE)
+    ose_debug ("iffp = 0x%x (%d)\n", iffp, iffp);
+
+  /* OK, we believe you.  You're a core file.  */
+
+  /* FIXME: this is too late here.  We'll want to record here things
+     like the core's pid, while inside read_pmd above.  Make this
+     allocation lazy within ose_core_tdata?  */
+  amt = sizeof (struct ose_core_struct);
+  abfd->tdata.ose_core_data = (struct ose_core_struct *) bfd_zmalloc (amt);
+  if (abfd->tdata.ose_core_data == NULL)
+    return NULL;
+
+  /* FIXME: should be set from what the PMD says it is.  */
+  bfd_default_set_arch_mach (abfd, bfd_arch_powerpc, bfd_mach_ppc);
+
+  return abfd->xvec;
+
+  /* Get here if we have already started filling out the BFD
+     and there is an error of some kind.  */
+
+  /* FIXME: not reacheable.  */
+  goto error_return;
+ error_return:
+  bfd_release (abfd, abfd->tdata.any);
+  abfd->tdata.any = NULL;
+  bfd_section_list_clear (abfd);
+  return NULL;
+}
+
+static char *
+ose_core_file_failing_command (bfd *abfd ATTRIBUTE_UNUSED)
+{
+  return NULL;
+}
+
+static int
+ose_core_file_failing_signal (bfd *abfd ATTRIBUTE_UNUSED)
+{
+  return abfd->tdata.ose_core_data->sig;
+}
+

+extern const bfd_target ose_core_little_vec;
+
+const bfd_target ose_core_big_vec =
+  {
+    "ose-core-big",
+    bfd_target_unknown_flavour,
+    BFD_ENDIAN_BIG,		/* target byte order */
+    BFD_ENDIAN_BIG,		/* target headers byte order */
+    (HAS_RELOC | EXEC_P |	/* object flags */
+     HAS_LINENO | HAS_DEBUG |
+     HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
+    (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
+    0,				/* symbol prefix */
+    ' ',			/* ar_pad_char */
+    16,				/* ar_max_namelen */
+    0,				/* match priority.  */
+    bfd_getb64, bfd_getb_signed_64, bfd_putb64,
+    bfd_getb32, bfd_getb_signed_32, bfd_putb32,
+    bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */
+    bfd_getb64, bfd_getb_signed_64, bfd_putb64,
+    bfd_getb32, bfd_getb_signed_32, bfd_putb32,
+    bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */
+
+    {				/* bfd_check_format */
+      _bfd_dummy_target,		/* unknown format */
+      _bfd_dummy_target,		/* object file */
+      _bfd_dummy_target,		/* archive */
+      ose_core_file_p	/* a core file */
+    },
+    {				/* bfd_set_format */
+      bfd_false, bfd_false,
+      bfd_false, bfd_false
+    },
+    {				/* bfd_write_contents */
+      bfd_false, bfd_false,
+      bfd_false, bfd_false
+    },
+
+    BFD_JUMP_TABLE_GENERIC (_bfd_generic),
+    BFD_JUMP_TABLE_COPY (_bfd_generic),
+    BFD_JUMP_TABLE_CORE (ose),
+    BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
+    BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols),
+    BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
+    BFD_JUMP_TABLE_WRITE (_bfd_generic),
+    BFD_JUMP_TABLE_LINK (_bfd_nolink),
+    BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
+
+    &ose_core_little_vec,
+
+    NULL      /* backend_data */
+  };
+
+const bfd_target ose_core_little_vec =
+  {
+    "ose-core-little",
+    bfd_target_unknown_flavour,
+    BFD_ENDIAN_LITTLE,		/* target byte order */
+    BFD_ENDIAN_LITTLE,		/* target headers byte order */
+    (HAS_RELOC | EXEC_P |	/* object flags */
+     HAS_LINENO | HAS_DEBUG |
+     HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
+    (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
+    0,				/* symbol prefix */
+    ' ',			/* ar_pad_char */
+    16,				/* ar_max_namelen */
+    0,				/* match priority.  */
+    bfd_getl64, bfd_getl_signed_64, bfd_putl64,
+    bfd_getl32, bfd_getl_signed_32, bfd_putl32,
+    bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */
+    bfd_getl64, bfd_getl_signed_64, bfd_putl64,
+    bfd_getl32, bfd_getl_signed_32, bfd_putl32,
+    bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */
+
+    {				/* bfd_check_format */
+      _bfd_dummy_target,		/* unknown format */
+      _bfd_dummy_target,		/* object file */
+      _bfd_dummy_target,		/* archive */
+      ose_core_file_p	/* a core file */
+    },
+    {				/* bfd_set_format */
+      bfd_false, bfd_false,
+      bfd_false, bfd_false
+    },
+    {				/* bfd_write_contents */
+      bfd_false, bfd_false,
+      bfd_false, bfd_false
+    },
+
+    BFD_JUMP_TABLE_GENERIC (_bfd_generic),
+    BFD_JUMP_TABLE_COPY (_bfd_generic),
+    BFD_JUMP_TABLE_CORE (ose),
+    BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
+    BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols),
+    BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
+    BFD_JUMP_TABLE_WRITE (_bfd_generic),
+    BFD_JUMP_TABLE_LINK (_bfd_nolink),
+    BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
+
+    &ose_core_big_vec,
+
+    NULL      /* backend_data */
+  };
--- a/bfd/targets.c
+++ b/bfd/targets.c
@@ -894,6 +894,8 @@ extern const bfd_target x86_64pei_vec;
 extern const bfd_target x86_64coff_vec;
 extern const bfd_target z80coff_vec;
 extern const bfd_target z8kcoff_vec;
+extern const bfd_target ose_core_big_vec;
+extern const bfd_target ose_core_little_vec;
 
 /* These are always included.  */
 extern const bfd_target srec_vec;



More information about the Binutils mailing list