--- 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 +#include +#include +#include +#include +#include + +#ifdef HAVE_ZLIB_H +#include +#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 + . 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() + DumpId ::= 'DPID' Size(4) U32() + BlockList ::= 'LIST' Size 'BLOC' (BlockForm)* + BlockForm ::= 'FORM' Size 'BLOC' (BlockChunk)* + BlockChunk ::= BlockHead | ErrorForm | TextForm | MemoryForm + BlockHead ::= 'BLHD' Size(16) U32() U32() + U32() + U32() + ErrorForm ::= 'FORM' Size 'ERBL' (Descr | ErrInfo)* + Descr ::= 'DESC' Size() + ErrInfo ::= 'ERIN' Size(16) U32() U32() + U32() U32() + TextForm ::= 'FORM' Size 'TXBL' (Descr)* + MemoryForm ::= 'FORM' Size 'MBL ' (Descr | (MemDef (Data | Zdata)))* + MemDef ::= 'MHD' Size(8) U32() U32() + Data ::= 'DATA' Size() + Zdata ::= 'FORM' Size 'ZDAT' Zdef Data + Zdef ::= 'ZDEF' Size U32() U32[4]() + U32() U32() +*/ + +/* 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, ¶meters[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() U32() U32() )* + */ + + 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;