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

Hui Zhu hui_zhu@mentor.com
Tue Mar 5 09:58:00 GMT 2013


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