aboutsummaryrefslogtreecommitdiff
path: root/binutils
diff options
context:
space:
mode:
authorDavid Henkel-Wallace <gumby@cygnus>1991-03-21 21:29:07 +0000
committerDavid Henkel-Wallace <gumby@cygnus>1991-03-21 21:29:07 +0000
commitc074abeebcefe3b62f46ff8a62f3d4058ed32780 (patch)
tree97a36afc00d9cc840b84d89e40ffbd13cd3ad7f7 /binutils
parent2fa0b342a5cd580781d2b9348a87f33a92d363fa (diff)
downloadgdb-c074abeebcefe3b62f46ff8a62f3d4058ed32780.zip
gdb-c074abeebcefe3b62f46ff8a62f3d4058ed32780.tar.gz
gdb-c074abeebcefe3b62f46ff8a62f3d4058ed32780.tar.bz2
Back from Intel with Steve
Diffstat (limited to 'binutils')
-rw-r--r--binutils/TODO11
-rw-r--r--binutils/alloca.c191
-rw-r--r--binutils/copy.c410
-rw-r--r--binutils/cplus-dem.c933
-rw-r--r--binutils/gmalloc.c1116
-rw-r--r--binutils/m68k-pinsn.c7
-rwxr-xr-xbinutils/ostrip.c418
-rw-r--r--binutils/sparc-pinsn.c7
-rwxr-xr-xbinutils/strip.c364
9 files changed, 3453 insertions, 4 deletions
diff --git a/binutils/TODO b/binutils/TODO
new file mode 100644
index 0000000..026f86c
--- /dev/null
+++ b/binutils/TODO
@@ -0,0 +1,11 @@
+o - merge:
+ copy and strip
+ ar and ranlib
+ nm, size, and objdump
+
+o - make the long options more consistent.
+
+o - make ATT and BSD versions -- perhaps the options should be
+ controlled by an environment variable.
+
+o - Calling +help or +version should exit with a successful status (ie 0)
diff --git a/binutils/alloca.c b/binutils/alloca.c
new file mode 100644
index 0000000..9639def
--- /dev/null
+++ b/binutils/alloca.c
@@ -0,0 +1,191 @@
+/*
+ alloca -- (mostly) portable public-domain implementation -- D A Gwyn
+
+ last edit: 86/05/30 rms
+ include config.h, since on VMS it renames some symbols.
+ Use xmalloc instead of malloc.
+
+ This implementation of the PWB library alloca() function,
+ which is used to allocate space off the run-time stack so
+ that it is automatically reclaimed upon procedure exit,
+ was inspired by discussions with J. Q. Johnson of Cornell.
+
+ It should work under any C implementation that uses an
+ actual procedure stack (as opposed to a linked list of
+ frames). There are some preprocessor constants that can
+ be defined when compiling for your specific system, for
+ improved efficiency; however, the defaults should be okay.
+
+ The general concept of this implementation is to keep
+ track of all alloca()-allocated blocks, and reclaim any
+ that are found to be deeper in the stack than the current
+ invocation. This heuristic does not reclaim storage as
+ soon as it becomes invalid, but it will do so eventually.
+
+ As a special case, alloca(0) reclaims storage without
+ allocating any. It is a good idea to use alloca(0) in
+ your main control loop, etc. to force garbage collection.
+*/
+#ifndef lint
+static char SCCSid[] = "@(#)alloca.c 1.1"; /* for the "what" utility */
+#endif
+
+#ifdef emacs
+#include "config.h"
+#ifdef static
+/* actually, only want this if static is defined as ""
+ -- this is for usg, in which emacs must undefine static
+ in order to make unexec workable
+ */
+#ifndef STACK_DIRECTION
+you
+lose
+-- must know STACK_DIRECTION at compile-time
+#endif /* STACK_DIRECTION undefined */
+#endif /* static */
+#endif /* emacs */
+
+#ifdef X3J11
+typedef void *pointer; /* generic pointer type */
+#else
+typedef char *pointer; /* generic pointer type */
+#endif
+
+#define NULL 0 /* null pointer constant */
+
+extern void free();
+extern pointer xmalloc();
+
+/*
+ Define STACK_DIRECTION if you know the direction of stack
+ growth for your system; otherwise it will be automatically
+ deduced at run-time.
+
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown
+*/
+
+#ifndef STACK_DIRECTION
+#define STACK_DIRECTION 0 /* direction unknown */
+#endif
+
+#if STACK_DIRECTION != 0
+
+#define STACK_DIR STACK_DIRECTION /* known at compile-time */
+
+#else /* STACK_DIRECTION == 0; need run-time code */
+
+static int stack_dir; /* 1 or -1 once known */
+#define STACK_DIR stack_dir
+
+static void
+find_stack_direction (/* void */)
+{
+ static char *addr = NULL; /* address of first
+ `dummy', once known */
+ auto char dummy; /* to get stack address */
+
+ if (addr == NULL)
+ { /* initial entry */
+ addr = &dummy;
+
+ find_stack_direction (); /* recurse once */
+ }
+ else /* second entry */
+ if (&dummy > addr)
+ stack_dir = 1; /* stack grew upward */
+ else
+ stack_dir = -1; /* stack grew downward */
+}
+
+#endif /* STACK_DIRECTION == 0 */
+
+/*
+ An "alloca header" is used to:
+ (a) chain together all alloca()ed blocks;
+ (b) keep track of stack depth.
+
+ It is very important that sizeof(header) agree with malloc()
+ alignment chunk size. The following default should work okay.
+*/
+
+#ifndef ALIGN_SIZE
+#define ALIGN_SIZE sizeof(double)
+#endif
+
+typedef union hdr
+{
+ char align[ALIGN_SIZE]; /* to force sizeof(header) */
+ struct
+ {
+ union hdr *next; /* for chaining headers */
+ char *deep; /* for stack depth measure */
+ } h;
+} header;
+
+/*
+ alloca( size ) returns a pointer to at least `size' bytes of
+ storage which will be automatically reclaimed upon exit from
+ the procedure that called alloca(). Originally, this space
+ was supposed to be taken from the current stack frame of the
+ caller, but that method cannot be made to work for some
+ implementations of C, for example under Gould's UTX/32.
+*/
+
+static header *last_alloca_header = NULL; /* -> last alloca header */
+
+pointer
+alloca (size) /* returns pointer to storage */
+ unsigned size; /* # bytes to allocate */
+{
+ auto char probe; /* probes stack depth: */
+ register char *depth = &probe;
+
+#if STACK_DIRECTION == 0
+ if (STACK_DIR == 0) /* unknown growth direction */
+ find_stack_direction ();
+#endif
+
+ /* Reclaim garbage, defined as all alloca()ed storage that
+ was allocated from deeper in the stack than currently. */
+
+ {
+ register header *hp; /* traverses linked list */
+
+ for (hp = last_alloca_header; hp != NULL;)
+ if (STACK_DIR > 0 && hp->h.deep > depth
+ || STACK_DIR < 0 && hp->h.deep < depth)
+ {
+ register header *np = hp->h.next;
+
+ free ((pointer) hp); /* collect garbage */
+
+ hp = np; /* -> next header */
+ }
+ else
+ break; /* rest are not deeper */
+
+ last_alloca_header = hp; /* -> last valid storage */
+ }
+
+ if (size == 0)
+ return NULL; /* no allocation required */
+
+ /* Allocate combined header + user data storage. */
+
+ {
+ register pointer new = xmalloc (sizeof (header) + size);
+ /* address of header */
+
+ ((header *)new)->h.next = last_alloca_header;
+ ((header *)new)->h.deep = depth;
+
+ last_alloca_header = (header *)new;
+
+ /* User storage begins just after header. */
+
+ return (pointer)((char *)new + sizeof(header));
+ }
+}
+
diff --git a/binutils/copy.c b/binutils/copy.c
new file mode 100644
index 0000000..601a2b7
--- /dev/null
+++ b/binutils/copy.c
@@ -0,0 +1,410 @@
+/*** copy.c -- copy object file from input to output, optionally massaging it */
+#include "sysdep.h"
+#include "bfd.h"
+
+asymbol **sympp;
+char *input_target = NULL;
+char *output_target = NULL;
+char *input_filename = NULL;
+char *output_filename = NULL;
+
+
+static void setup_sections();
+static void copy_sections();
+static boolean strip;
+static boolean verbose;
+
+/* IMPORTS */
+extern char *program_name;
+extern char *xmalloc();
+
+static
+void
+usage()
+{
+ fprintf(stderr,
+ "Usage %s [-S][-s srcfmt] [-d dtfmt] [-b bothfmts] infile [outfile]\n",
+ program_name);
+ exit(1);
+}
+
+
+/* Create a temp file in the same directory as supplied */
+static
+char *
+make_tempname(filename)
+char *filename;
+{
+ static char template[] = "stXXXXXX";
+ char *tmpname;
+ char * slash = strrchr( filename, '/' );
+ if (slash != (char *)NULL){
+ *slash = 0;
+ tmpname = xmalloc(strlen(filename) + sizeof(template) + 1 );
+ strcpy(tmpname, filename);
+ strcat(tmpname, "/" );
+ strcat(tmpname, template);
+ mktemp(tmpname );
+ *slash = '/';
+ } else {
+ tmpname = xmalloc(sizeof(template));
+ strcpy(tmpname, template);
+ mktemp(tmpname);
+ }
+ return tmpname;
+}
+
+/*
+ All the symbols have been read in and point to their owning input section.
+ They have been relocated to that they are all relative to the base of
+ their owning section. On the way out, all the symbols will be relocated to
+ their new location in the output file, through some complex sums.
+
+*/
+static void
+mangle_sections(ibfd, obfd)
+ bfd *ibfd;
+ bfd *obfd;
+{
+ asection *current = ibfd->sections;
+ for (; current != NULL; current = current->next) {
+ current->output_section = bfd_get_section_by_name(obfd, current->name);
+ current->output_offset = 0;
+ }
+}
+
+static
+void
+copy_object(ibfd, obfd)
+bfd *ibfd;
+bfd *obfd;
+{
+
+ unsigned int symcount;
+
+
+ if (!bfd_set_format(obfd, bfd_get_format(ibfd)))
+ bfd_fatal(output_filename);
+
+
+ if (verbose)
+ printf("copy from %s(%s) to %s(%s)\n",
+ ibfd->filename, ibfd->xvec->name,
+ obfd->filename, obfd->xvec->name);
+
+ if ((bfd_set_start_address(obfd, bfd_get_start_address(ibfd)) == false) ||
+ (bfd_set_file_flags(obfd, (bfd_get_file_flags(ibfd) &
+ ~(HAS_LINENO | HAS_DEBUG | HAS_SYMS | D_PAGED |
+ HAS_LOCALS))) == false) ||
+ bfd_set_start_address(obfd, bfd_get_start_address(ibfd)) == false)
+ bfd_fatal(bfd_get_filename(ibfd));
+
+ /* Copy architecture of input file to output file */
+ if (!bfd_set_arch_mach(obfd, bfd_get_architecture(ibfd),
+ bfd_get_machine(ibfd))) {
+ fprintf(stderr, "Output file cannot represent architecture %s\n",
+ bfd_printable_arch_mach(bfd_get_architecture(ibfd),
+ bfd_get_machine(ibfd)));
+ }
+ if (!bfd_set_format(obfd, bfd_get_format(ibfd)))
+ {
+ bfd_fatal(ibfd->filename);
+ }
+
+ sympp = (asymbol **) xmalloc(get_symtab_upper_bound(ibfd));
+ symcount = bfd_canonicalize_symtab(ibfd, sympp);
+
+ bfd_set_symtab(obfd, sympp, strip == true ? 0 : symcount);
+
+ /*
+ bfd mandates that all output sections be created and sizes set before
+ any output is done. Thus, we traverse all sections twice.
+ */
+ bfd_map_over_sections(ibfd, setup_sections, (void *) obfd);
+ bfd_map_over_sections(ibfd, copy_sections, (void *) obfd);
+ mangle_sections(ibfd, obfd);
+}
+static
+char *
+cat(a,b,c)
+char *a;
+char *b;
+char *c;
+{
+ int size = strlen(a) + strlen(b) + strlen(c);
+ char *r = xmalloc(size+1);
+ strcpy(r,a);
+ strcat(r,b);
+ strcat(r,c);
+ return r;
+}
+
+static void
+copy_archive(ibfd, obfd)
+bfd *ibfd;
+bfd *obfd;
+{
+ bfd **ptr =&( obfd->archive_head);
+ bfd *this_element;
+ /* Read each archive element in turn from the input, copy the
+ contents to a temp file, and keep the temp file handle */
+ char *dir = cat("./",make_tempname(this_element->filename),"copy-dir");
+
+ /* Make a temp directory to hold the contents */
+ mkdir(dir,0777);
+ obfd->has_armap = ibfd->has_armap;
+ this_element = bfd_openr_next_archived_file(ibfd, NULL);
+ while (this_element != (bfd *)NULL) {
+
+ /* Create an output file for this member */
+ char *output_name = cat(dir, "/",this_element->filename);
+ bfd *output_bfd = bfd_openw(output_name, output_target);
+
+ if (!bfd_set_format(obfd, bfd_get_format(ibfd)))
+ bfd_fatal(output_filename);
+
+ if (output_bfd == (bfd *)NULL) {
+ bfd_fatal(output_name);
+ }
+ if (bfd_check_format(this_element, bfd_object) == true) {
+ copy_object(this_element, output_bfd);
+ }
+
+ bfd_close(output_bfd);
+ /* Now open the newly output file and attatch to our list */
+ output_bfd = bfd_openr(output_name, output_target);
+ /* Mark it for deletion */
+
+ *ptr = output_bfd;
+
+ ptr =&( output_bfd->next);
+ this_element = bfd_openr_next_archived_file(ibfd, this_element);
+
+ }
+ *ptr = (bfd *)NULL;
+
+ if (!bfd_close(obfd))
+ bfd_fatal(output_filename);
+
+ /* Now delete all the files that we opened
+ We can't use the names in the obfd list since they may have been
+ trampled by the archive output code
+ */
+ for (this_element = ibfd->archive_head;
+ this_element != (bfd *)NULL;
+ this_element = this_element->next)
+ {
+ unlink(cat(dir,"/",this_element->filename));
+ }
+ unlink(dir);
+ if (!bfd_close(ibfd))
+ bfd_fatal(input_filename);
+
+}
+
+static
+boolean
+copy_file(input_filename, output_filename)
+ char *input_filename;
+ char *output_filename;
+{
+ bfd *ibfd;
+
+
+ ibfd = bfd_openr(input_filename, input_target);
+ if (ibfd == NULL)
+ bfd_fatal(input_filename);
+
+ if (bfd_check_format(ibfd, bfd_object)) {
+ bfd * obfd = bfd_openw(output_filename, output_target);
+ if (obfd == NULL)
+ bfd_fatal(output_filename);
+
+ copy_object(ibfd, obfd);
+
+ if (!bfd_close(obfd))
+ bfd_fatal(output_filename);
+
+ if (!bfd_close(ibfd))
+ bfd_fatal(input_filename);
+ }
+ else if (bfd_check_format(ibfd, bfd_archive)) {
+ bfd * obfd = bfd_openw(output_filename, output_target);
+ if (obfd == NULL)
+ bfd_fatal(output_filename);
+
+ copy_archive(ibfd, obfd);
+ }
+}
+
+
+
+/** Actually do the work */
+static void
+setup_sections(ibfd, isection, obfd)
+ bfd *ibfd;
+ sec_ptr isection;
+ bfd *obfd;
+{
+ sec_ptr osection;
+ char *err;
+ osection = bfd_make_section(obfd, bfd_section_name(ibfd, isection));
+ if (osection == NULL) {
+ err = "making";
+ goto loser;
+ }
+
+ if (!bfd_set_section_size(obfd,
+ osection,
+ bfd_section_size(ibfd, isection))) {
+ err = "size";
+ goto loser;
+ }
+
+ if (bfd_set_section_vma(obfd,
+ osection,
+ bfd_section_vma(ibfd, isection))
+ == false) {
+ err = "vma";
+ goto loser;
+ } /* on error */
+
+ if (bfd_set_section_alignment(obfd,
+ osection,
+ bfd_section_alignment(ibfd, isection))
+ == false) {
+ err = "alignment";
+ goto loser;
+ } /* on error */
+
+ if (!bfd_set_section_flags(obfd, osection,
+ bfd_get_section_flags(ibfd, isection))) {
+ err = "flags";
+ goto loser;
+ }
+
+ /* All went well */
+ return;
+
+loser:
+ fprintf(stderr, "%s: file \"%s\", section \"%s\": error in %s: %s\n",
+ program_name,
+ bfd_get_filename(ibfd), bfd_section_name(ibfd, isection),
+ err, bfd_errmsg(bfd_error));
+ exit(1);
+} /* setup_sections() */
+
+static void
+copy_sections(ibfd, isection, obfd)
+ bfd *ibfd;
+ sec_ptr isection;
+ bfd *obfd;
+{
+ static unsigned char *memhunk = NULL;
+ arelent **relpp;
+ int relcount;
+ sec_ptr osection;
+ unsigned long size;
+ osection = bfd_get_section_by_name(obfd,
+ bfd_section_name(ibfd, isection));
+
+ size = bfd_section_size(ibfd, isection);
+
+ if (size == 0)
+ return;
+
+ if (get_reloc_upper_bound(ibfd, isection) != 0) {
+ relpp = (arelent **) xmalloc(get_reloc_upper_bound(ibfd, isection));
+
+ relcount = bfd_canonicalize_reloc(ibfd, isection, relpp, sympp);
+
+ bfd_set_reloc(obfd, osection, relpp, relcount);
+ }
+
+ if (bfd_get_section_flags(ibfd, isection) & SEC_HAS_CONTENTS) {
+ memhunk = (unsigned char *) xmalloc(size);
+ /* now we have enough memory, just do it: */
+ if (!bfd_get_section_contents(ibfd, isection, memhunk, 0, size))
+ bfd_fatal(bfd_get_filename(ibfd));
+
+ if (!bfd_set_section_contents(obfd, osection, memhunk, 0, size))
+ bfd_fatal(bfd_get_filename(obfd));
+ } /* only if the section has contents. */
+
+ free(memhunk);
+}
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int i;
+
+
+ program_name = argv[0];
+
+ if (strcmp(program_name,"strip") == 0) {
+ strip = true;
+ }
+
+ for (i = 1; i < argc; i++)
+ {
+ if (argv[i][0] == '-') {
+ switch (argv[i][1]) {
+ case 'v':
+ verbose = true;
+ break;
+ case 'b':
+ i++;
+ input_target = output_target = argv[i];
+ break;
+ case 'S':
+ strip = true;
+ break;
+ case 's':
+ i++;
+ input_target = argv[i];
+ break;
+ case 'd':
+ i++;
+ output_target = argv[i];
+ break;
+ default:
+ usage();
+ }
+ }
+ else {
+ if (input_filename) {
+ output_filename = argv[i];
+ }
+ else {
+ input_filename = argv[i];
+ }
+ }
+ }
+
+ if (input_filename == (char *) NULL)
+ usage();
+
+ if (output_target == (char *) NULL)
+ output_target = input_target;
+
+ /* If there is no destination file then create a temp and rename
+ the result into the input */
+
+ if (output_filename == (char *)NULL) {
+ char * tmpname = make_tempname(input_filename);
+ if (copy_file(input_filename, tmpname)) {
+ output_filename = input_filename;
+ rename(tmpname, input_filename);
+ return 0;
+ }
+ }
+ else if (copy_file(input_filename, output_filename))
+ {
+ return 0;
+ }
+
+
+ return 1;
+}
diff --git a/binutils/cplus-dem.c b/binutils/cplus-dem.c
new file mode 100644
index 0000000..4cc6496
--- /dev/null
+++ b/binutils/cplus-dem.c
@@ -0,0 +1,933 @@
+/* Demangler for GNU C++
+ Copyright (C) 1989 Free Software Foundation, Inc.
+ written by James Clark (jjc@jclark.uucp)
+
+ 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This is for g++ 1.36.1 (November 6 version). It will probably
+ require changes for any other version.
+
+ Modified for g++ 1.36.2 (November 18 version). */
+
+/* This file exports one function
+
+ char *cplus_demangle (const char *name)
+
+ If `name' is a mangled function name produced by g++, then
+ a pointer to a malloced string giving a C++ representation
+ of the name will be returned; otherwise NULL will be returned.
+ It is the caller's responsibility to free the string which
+ is returned.
+
+ For example,
+
+ cplus_demangle ("_foo__1Ai")
+
+ returns
+
+ "A::foo(int)"
+
+ This file imports xmalloc and xrealloc, which are like malloc and
+ realloc except that they generate a fatal error if there is no
+ available memory. */
+
+#if 0 /* Should really be part of BFD */
+#define nounderscore 1 /* define this is names don't start with _ */
+#endif
+#include "sysdep.h"
+
+#include <ctype.h>
+
+#ifndef __STDC__
+#define const
+#endif
+
+#ifdef __STDC__
+extern char *cplus_demangle (const char *type);
+#else
+extern char *cplus_demangle ();
+#endif
+
+static char **typevec = 0;
+static int ntypes = 0;
+static int typevec_size = 0;
+
+static struct {
+ const char *in;
+ const char *out;
+} optable[] = {
+ "new", " new",
+ "delete", " delete",
+ "ne", "!=",
+ "eq", "==",
+ "ge", ">=",
+ "gt", ">",
+ "le", "<=",
+ "lt", "<",
+ "plus", "+",
+ "minus", "-",
+ "mult", "*",
+ "convert", "+", /* unary + */
+ "negate", "-", /* unary - */
+ "trunc_mod", "%",
+ "trunc_div", "/",
+ "truth_andif", "&&",
+ "truth_orif", "||",
+ "truth_not", "!",
+ "postincrement", "++",
+ "postdecrement", "--",
+ "bit_ior", "|",
+ "bit_xor", "^",
+ "bit_and", "&",
+ "bit_not", "~",
+ "call", "()",
+ "cond", "?:",
+ "alshift", "<<",
+ "arshift", ">>",
+ "component", "->",
+ "indirect", "*",
+ "method_call", "->()",
+ "addr", "&", /* unary & */
+ "array", "[]",
+ "nop", "", /* for operator= */
+};
+
+/* Beware: these aren't '\0' terminated. */
+
+typedef struct {
+ char *b; /* pointer to start of string */
+ char *p; /* pointer after last character */
+ char *e; /* pointer after end of allocated space */
+} string;
+
+#ifdef __STDC__
+static void string_need (string *s, int n);
+static void string_delete (string *s);
+static void string_init (string *s);
+static void string_clear (string *s);
+static int string_empty (string *s);
+static void string_append (string *p, const char *s);
+static void string_appends (string *p, string *s);
+static void string_appendn (string *p, const char *s, int n);
+static void string_prepend (string *p, const char *s);
+#if 0
+static void string_prepends (string *p, string *s);
+#endif
+static void string_prependn (string *p, const char *s, int n);
+static int get_count (const char **type, int *count);
+static int do_args (const char **type, string *decl);
+static int do_type (const char **type, string *result);
+static int do_arg (const char **type, string *result);
+static int do_args (const char **type, string *decl);
+static void munge_function_name (string *name);
+#else
+static void string_need ();
+static void string_delete ();
+static void string_init ();
+static void string_clear ();
+static int string_empty ();
+static void string_append ();
+static void string_appends ();
+static void string_appendn ();
+static void string_prepend ();
+static void string_prepends ();
+static void string_prependn ();
+static int get_count ();
+static int do_args ();
+static int do_type ();
+static int do_arg ();
+static int do_args ();
+static void munge_function_name ();
+#endif
+
+char *
+cplus_demangle (type)
+ const char *type;
+{
+ string decl;
+ int n;
+ int success = 0;
+ int constructor = 0;
+ int const_flag = 0;
+ int i;
+ const char *p, *premangle;
+
+ if (type == NULL || *type == '\0')
+ return NULL;
+#ifndef nounderscore
+ if (*type++ != '_')
+ return NULL;
+#endif
+ p = type;
+ while (*p != '\0' && !(*p == '_' && p[1] == '_'))
+ p++;
+ if (*p == '\0')
+ {
+ /* destructor */
+ if (type[0] == '_' && type[1] == '$' && type[2] == '_')
+ {
+ unsigned int l = (strlen (type) - 3)*2 + 3 + 2 + 1;
+ char *tem = (char *) xmalloc (l);
+ strcpy (tem, type + 3);
+ strcat (tem, "::~");
+ strcat (tem, type + 3);
+ strcat (tem, "()");
+ return tem;
+ }
+ /* static data member */
+ if (*type != '_' && (p = (char *) strchr (type, '$')) != NULL)
+ {
+ int n = strlen (type) + 2;
+ char *tem = (char *) xmalloc (n);
+ memcpy (tem, type, p - type);
+ strcpy (tem + (p - type), "::");
+ strcpy (tem + (p - type) + 2, p + 1);
+ return tem;
+ }
+ /* virtual table */
+ if (type[0] == '_' && type[1] == 'v' && type[2] == 't' && type[3] == '$')
+ {
+ int n = strlen (type + 4) + 14 + 1;
+ char *tem = (char *) xmalloc (n);
+ strcpy (tem, type + 4);
+ strcat (tem, " virtual table");
+ return tem;
+ }
+ return NULL;
+ }
+
+ string_init (&decl);
+
+ if (p == type)
+ {
+ if (!isdigit (p[2]))
+ {
+ string_delete (&decl);
+ return NULL;
+ }
+ constructor = 1;
+ }
+ else
+ {
+ string_appendn (&decl, type, p - type);
+ munge_function_name (&decl);
+ }
+ p += 2;
+
+ premangle = p;
+ switch (*p)
+ {
+ case 'C':
+ /* a const member function */
+ if (!isdigit (p[1]))
+ {
+ string_delete (&decl);
+ return NULL;
+ }
+ p += 1;
+ const_flag = 1;
+ /* fall through */
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ n = 0;
+ do
+ {
+ n *= 10;
+ n += *p - '0';
+ p += 1;
+ }
+ while (isdigit (*p));
+ if (strlen (p) < n)
+ {
+ string_delete (&decl);
+ return NULL;
+ }
+ if (constructor)
+ {
+ string_appendn (&decl, p, n);
+ string_append (&decl, "::");
+ string_appendn (&decl, p, n);
+ }
+ else
+ {
+ string_prepend (&decl, "::");
+ string_prependn (&decl, p, n);
+ }
+#ifndef LONGERNAMES
+ p = premangle;
+#else
+ p += n;
+#endif
+ success = do_args (&p, &decl);
+ if (const_flag)
+ string_append (&decl, " const");
+ break;
+ case 'F':
+ p += 1;
+ success = do_args (&p, &decl);
+ break;
+ }
+
+ for (i = 0; i < ntypes; i++)
+ if (typevec[i] != NULL)
+ free (typevec[i]);
+ ntypes = 0;
+ if (typevec != NULL)
+ {
+ free ((char *)typevec);
+ typevec = NULL;
+ typevec_size = 0;
+ }
+
+ if (success)
+ {
+ string_appendn (&decl, "", 1);
+ return decl.b;
+ }
+ else
+ {
+ string_delete (&decl);
+ return NULL;
+ }
+}
+
+static int
+get_count (type, count)
+ const char **type;
+ int *count;
+{
+ if (!isdigit (**type))
+ return 0;
+ *count = **type - '0';
+ *type += 1;
+ /* see flush_repeats in cplus-method.c */
+ if (isdigit (**type))
+ {
+ const char *p = *type;
+ int n = *count;
+ do
+ {
+ n *= 10;
+ n += *p - '0';
+ p += 1;
+ }
+ while (isdigit (*p));
+ if (*p == '_')
+ {
+ *type = p + 1;
+ *count = n;
+ }
+ }
+ return 1;
+}
+
+/* result will be initialised here; it will be freed on failure */
+
+static int
+do_type (type, result)
+ const char **type;
+ string *result;
+{
+ int n;
+ int done;
+ int non_empty = 0;
+ int success;
+ string decl;
+ const char *remembered_type;
+
+ string_init (&decl);
+ string_init (result);
+
+ done = 0;
+ success = 1;
+ while (success && !done)
+ {
+ int member;
+ switch (**type)
+ {
+ case 'P':
+ *type += 1;
+ string_prepend (&decl, "*");
+ break;
+
+ case 'R':
+ *type += 1;
+ string_prepend (&decl, "&");
+ break;
+
+ case 'T':
+ *type += 1;
+ if (!get_count (type, &n) || n >= ntypes)
+ success = 0;
+ else
+ {
+ remembered_type = typevec[n];
+ type = &remembered_type;
+ }
+ break;
+
+ case 'F':
+ *type += 1;
+ if (!string_empty (&decl) && decl.b[0] == '*')
+ {
+ string_prepend (&decl, "(");
+ string_append (&decl, ")");
+ }
+ if (!do_args (type, &decl) || **type != '_')
+ success = 0;
+ else
+ *type += 1;
+ break;
+
+ case 'M':
+ case 'O':
+ {
+ int constp = 0;
+ int volatilep = 0;
+
+ member = **type == 'M';
+ *type += 1;
+ if (!isdigit (**type))
+ {
+ success = 0;
+ break;
+ }
+ n = 0;
+ do
+ {
+ n *= 10;
+ n += **type - '0';
+ *type += 1;
+ }
+ while (isdigit (**type));
+ if (strlen (*type) < n)
+ {
+ success = 0;
+ break;
+ }
+ string_append (&decl, ")");
+ string_prepend (&decl, "::");
+ string_prependn (&decl, *type, n);
+ string_prepend (&decl, "(");
+ *type += n;
+ if (member)
+ {
+ if (**type == 'C')
+ {
+ *type += 1;
+ constp = 1;
+ }
+ if (**type == 'V')
+ {
+ *type += 1;
+ volatilep = 1;
+ }
+ if (*(*type)++ != 'F')
+ {
+ success = 0;
+ break;
+ }
+ }
+ if ((member && !do_args (type, &decl)) || **type != '_')
+ {
+ success = 0;
+ break;
+ }
+ *type += 1;
+ if (constp)
+ {
+ if (non_empty)
+ string_append (&decl, " ");
+ else
+ non_empty = 1;
+ string_append (&decl, "const");
+ }
+ if (volatilep)
+ {
+ if (non_empty)
+ string_append (&decl, " ");
+ else
+ non_empty = 1;
+ string_append (&decl, "volatilep");
+ }
+ break;
+ }
+
+ case 'C':
+ if ((*type)[1] == 'P')
+ {
+ *type += 1;
+ if (!string_empty (&decl))
+ string_prepend (&decl, " ");
+ string_prepend (&decl, "const");
+ break;
+ }
+
+ /* fall through */
+ default:
+ done = 1;
+ break;
+ }
+ }
+
+ done = 0;
+ non_empty = 0;
+ while (success && !done)
+ {
+ switch (**type)
+ {
+ case 'C':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ else
+ non_empty = 1;
+ string_append (result, "const");
+ break;
+ case 'U':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ else
+ non_empty = 1;
+ string_append (result, "unsigned");
+ break;
+ case 'V':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ else
+ non_empty = 1;
+ string_append (result, "volatile");
+ break;
+ default:
+ done = 1;
+ break;
+ }
+ }
+
+ if (success)
+ switch (**type)
+ {
+ case '\0':
+ case '_':
+ break;
+ case 'v':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ string_append (result, "void");
+ break;
+ case 'l':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ string_append (result, "long");
+ break;
+ case 'i':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ string_append (result, "int");
+ break;
+ case 's':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ string_append (result, "short");
+ break;
+ case 'c':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ string_append (result, "char");
+ break;
+ case 'r':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ string_append (result, "long double");
+ break;
+ case 'd':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ string_append (result, "double");
+ break;
+ case 'f':
+ *type += 1;
+ if (non_empty)
+ string_append (result, " ");
+ string_append (result, "float");
+ break;
+ case 'G':
+ *type += 1;
+ if (!isdigit (**type))
+ {
+ success = 0;
+ break;
+ }
+ /* fall through */
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ n = 0;
+ do
+ {
+ n *= 10;
+ n += **type - '0';
+ *type += 1;
+ }
+ while (isdigit (**type));
+ if (strlen (*type) < n)
+ {
+ success = 0;
+ break;
+ }
+ if (non_empty)
+ string_append (result, " ");
+ string_appendn (result, *type, n);
+ *type += n;
+ break;
+ default:
+ success = 0;
+ break;
+ }
+
+ if (success)
+ {
+ if (!string_empty (&decl))
+ {
+ string_append (result, " ");
+ string_appends (result, &decl);
+ }
+ string_delete (&decl);
+ return 1;
+ }
+ else
+ {
+ string_delete (&decl);
+ string_delete (result);
+ return 0;
+ }
+}
+
+/* `result' will be initialised in do_type; it will be freed on failure */
+
+static int
+do_arg (type, result)
+ const char **type;
+ string *result;
+{
+ char *tem;
+ int len;
+ const char *start;
+ const char *end;
+
+ start = *type;
+ if (!do_type (type, result))
+ return 0;
+ end = *type;
+ if (ntypes >= typevec_size)
+ {
+ if (typevec_size == 0)
+ {
+ typevec_size = 3;
+ typevec = (char **) xmalloc (sizeof (char*)*typevec_size);
+ }
+ else
+ {
+ typevec_size *= 2;
+ typevec = (char **) xrealloc ((char *)typevec, sizeof (char*)*typevec_size);
+ }
+ }
+ len = end - start;
+ tem = (char *) xmalloc (len + 1);
+ memcpy (tem, start, len);
+ tem[len] = '\0';
+ typevec[ntypes++] = tem;
+ return 1;
+}
+
+/* `decl' must be already initialised, usually non-empty;
+ it won't be freed on failure */
+
+static int
+do_args (type, decl)
+ const char **type;
+ string *decl;
+{
+ string arg;
+ int need_comma = 0;
+ int dont_want_first;
+
+#ifndef LONGERNAMES
+ dont_want_first = 1;
+#else
+ dont_want_first = 0;
+#endif
+
+ string_append (decl, "(");
+
+ while (**type != '_' && **type != '\0' && **type != 'e' && **type != 'v')
+ {
+ if (**type == 'N')
+ {
+ int r;
+ int t;
+ *type += 1;
+ if (!get_count (type, &r) || !get_count (type, &t) || t >= ntypes)
+ return 0;
+ while (--r >= 0)
+ {
+ const char *tem = typevec[t];
+ if (need_comma)
+ string_append (decl, ", ");
+ if (!do_arg (&tem, &arg))
+ return 0;
+ string_appends (decl, &arg);
+ string_delete (&arg);
+ need_comma = 1;
+ }
+ }
+ else
+ {
+ if (need_comma)
+ string_append (decl, ", ");
+ if (!do_arg (type, &arg))
+ return 0;
+ if (dont_want_first)
+ dont_want_first = 0;
+ else
+ {
+ string_appends (decl, &arg);
+ need_comma = 1;
+ }
+ string_delete (&arg);
+ }
+ }
+
+ if (**type == 'v')
+ *type += 1;
+ else if (**type == 'e')
+ {
+ *type += 1;
+ if (need_comma)
+ string_append (decl, ",");
+ string_append (decl, "...");
+ }
+
+ string_append (decl, ")");
+ return 1;
+}
+
+static void
+munge_function_name (name)
+ string *name;
+{
+ if (!string_empty (name) && name->p - name->b >= 3
+ && name->b[0] == 'o' && name->b[1] == 'p' && name->b[2] == '$')
+ {
+ unsigned int i;
+ /* see if it's an assignment expression */
+ if (name->p - name->b >= 10 /* op$assign_ */
+ && memcmp (name->b + 3, "assign_", 7) == 0)
+ {
+ for (i = 0; i < sizeof (optable)/sizeof (optable[0]); i++)
+ {
+ int len = name->p - name->b - 10;
+ if (strlen (optable[i].in) == len
+ && memcmp (optable[i].in, name->b + 10, len) == 0)
+ {
+ string_clear (name);
+ string_append (name, "operator");
+ string_append (name, optable[i].out);
+ string_append (name, "=");
+ return;
+ }
+ }
+ }
+ else
+ {
+ for (i = 0; i < sizeof (optable)/sizeof (optable[0]); i++)
+ {
+ int len = name->p - name->b - 3;
+ if (strlen (optable[i].in) == len
+ && memcmp (optable[i].in, name->b + 3, len) == 0)
+ {
+ string_clear (name);
+ string_append (name, "operator");
+ string_append (name, optable[i].out);
+ return;
+ }
+ }
+ }
+ return;
+ }
+ else if (!string_empty (name) && name->p - name->b >= 5
+ && memcmp (name->b, "type$", 5) == 0)
+ {
+ /* type conversion operator */
+ string type;
+ const char *tem = name->b + 5;
+ if (do_type (&tem, &type))
+ {
+ string_clear (name);
+ string_append (name, "operator ");
+ string_appends (name, &type);
+ string_delete (&type);
+ return;
+ }
+ }
+}
+
+/* a mini string-handling package */
+
+static void
+string_need (s, n)
+ string *s;
+ int n;
+{
+ if (s->b == NULL)
+ {
+ if (n < 32)
+ n = 32;
+ s->p = s->b = (char *) xmalloc (n);
+ s->e = s->b + n;
+ }
+ else if (s->e - s->p < n)
+ {
+ int tem = s->p - s->b;
+ n += tem;
+ n *= 2;
+ s->b = (char *) xrealloc (s->b, n);
+ s->p = s->b + tem;
+ s->e = s->b + n;
+ }
+}
+
+static void
+string_delete (s)
+ string *s;
+{
+ if (s->b != NULL)
+ {
+ free (s->b);
+ s->b = s->e = s->p = NULL;
+ }
+}
+
+static void
+string_init (s)
+ string *s;
+{
+ s->b = s->p = s->e = NULL;
+}
+
+static void
+string_clear (s)
+ string *s;
+{
+ s->p = s->b;
+}
+
+static int
+string_empty (s)
+ string *s;
+{
+ return s->b == s->p;
+}
+
+static void
+string_append (p, s)
+ string *p;
+ const char *s;
+{
+ int n;
+ if (s == NULL || *s == '\0')
+ return;
+ n = strlen (s);
+ string_need (p, n);
+ memcpy (p->p, s, n);
+ p->p += n;
+}
+
+static void
+string_appends (p, s)
+ string *p, *s;
+{
+ int n;
+ if (s->b == s->p)
+ return;
+ n = s->p - s->b;
+ string_need (p, n);
+ memcpy (p->p, s->b, n);
+ p->p += n;
+}
+
+static void
+string_appendn (p, s, n)
+ string *p;
+ const char *s;
+ int n;
+{
+ if (n == 0)
+ return;
+ string_need (p, n);
+ memcpy (p->p, s, n);
+ p->p += n;
+}
+
+static void
+string_prepend (p, s)
+ string *p;
+ const char *s;
+{
+ if (s == NULL || *s == '\0')
+ return;
+ string_prependn (p, s, strlen (s));
+}
+
+static void
+string_prependn (p, s, n)
+ string *p;
+ const char *s;
+ int n;
+{
+ char *q;
+
+ if (n == 0)
+ return;
+ string_need (p, n);
+ for (q = p->p - 1; q >= p->b; q--)
+ q[n] = q[0];
+ memcpy (p->b, s, n);
+ p->p += n;
+}
diff --git a/binutils/gmalloc.c b/binutils/gmalloc.c
new file mode 100644
index 0000000..0468551
--- /dev/null
+++ b/binutils/gmalloc.c
@@ -0,0 +1,1116 @@
+
+/* gmalloc.c - THIS FILE IS AUTOMAGICALLY GENERATED SO DON'T EDIT IT. */
+
+/* Single-file skeleton for GNU malloc.
+ Copyright 1989 Free Software Foundation
+ Written May 1989 by Mike Haertel.
+
+ 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author may be reached (Email) at the address mike@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#define __ONEFILE
+
+/* DO NOT DELETE THIS LINE -- ansidecl.h INSERTED HERE. */
+/* Copyright (C) 1989 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library 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 1, or (at your option)
+any later version.
+
+The GNU C Library 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 the GNU C Library; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* ANSI and traditional C compatibility macros
+
+ ANSI C is assumed if __STDC__ is #defined.
+
+ Macros
+ PTR - Generic pointer type
+ LONG_DOUBLE - `long double' type
+ CONST - `const' keyword
+ VOLATILE - `volatile' keyword
+ SIGNED - `signed' keyword
+ PTRCONST - Generic const pointer (void *const)
+
+ EXFUN(name, prototype) - declare external function NAME
+ with prototype PROTOTYPE
+ DEFUN(name, arglist, args) - define function NAME with
+ args ARGLIST of types in ARGS
+ DEFUN_VOID(name) - define function NAME with no args
+ AND - argument separator for ARGS
+ NOARGS - null arglist
+ DOTS - `...' in args
+
+ For example:
+ extern int EXFUN(printf, (CONST char *format DOTS));
+ int DEFUN(fprintf, (stream, format),
+ FILE *stream AND CONST char *format DOTS) { ... }
+ void DEFUN_VOID(abort) { ... }
+*/
+
+#ifndef _ANSIDECL_H
+
+#define _ANSIDECL_H 1
+
+
+/* Every source file includes this file,
+ so they will all get the switch for lint. */
+/* LINTLIBRARY */
+
+
+#ifdef __STDC__
+
+#define PTR void *
+#define PTRCONST void *CONST
+#define LONG_DOUBLE long double
+
+#define AND ,
+#define NOARGS void
+#define CONST const
+#define VOLATILE volatile
+#define SIGNED signed
+#define DOTS , ...
+
+#define EXFUN(name, proto) name proto
+#define DEFUN(name, arglist, args) name(args)
+#define DEFUN_VOID(name) name(NOARGS)
+
+#else /* Not ANSI C. */
+
+#define PTR char *
+#define PTRCONST PTR
+#define LONG_DOUBLE double
+
+#define AND ;
+#define NOARGS
+#define CONST
+#define VOLATILE
+#define SIGNED
+#define DOTS
+
+#define EXFUN(name, proto) name()
+#define DEFUN(name, arglist, args) name arglist args;
+#define DEFUN_VOID(name) name()
+
+#endif /* ANSI C. */
+
+
+#endif /* ansidecl.h */
+
+#ifdef __STDC__
+#include <limits.h>
+#else
+/* DO NOT DELETE THIS LINE -- limits.h INSERTED HERE. */
+/* Number of bits in a `char'. */
+#define CHAR_BIT 8
+
+/* No multibyte characters supported yet. */
+#define MB_LEN_MAX 1
+
+/* Minimum and maximum values a `signed char' can hold. */
+#define SCHAR_MIN -128
+#define SCHAR_MAX 127
+
+/* Maximum value an `unsigned char' can hold. (Minimum is 0). */
+#define UCHAR_MAX 255U
+
+/* Minimum and maximum values a `char' can hold. */
+#ifdef __CHAR_UNSIGNED__
+#define CHAR_MIN 0
+#define CHAR_MAX 255U
+#else
+#define CHAR_MIN -128
+#define CHAR_MAX 127
+#endif
+
+/* Minimum and maximum values a `signed short int' can hold. */
+#define SHRT_MIN -32768
+#define SHRT_MAX 32767
+
+/* Maximum value an `unsigned short int' can hold. (Minimum is 0). */
+#define USHRT_MAX 65535U
+
+/* Minimum and maximum values a `signed int' can hold. */
+#define INT_MIN -2147483648
+#define INT_MAX 2147483647
+
+/* Maximum value an `unsigned int' can hold. (Minimum is 0). */
+#define UINT_MAX 4294967295U
+
+/* Minimum and maximum values a `signed long int' can hold.
+ (Same as `int'). */
+#define LONG_MIN (-LONG_MAX-1)
+#define LONG_MAX 2147483647
+
+/* Maximum value an `unsigned long int' can hold. (Minimum is 0). */
+#define ULONG_MAX 4294967295U
+#endif
+
+#ifdef __STDC__
+#include <stddef.h>
+#else
+/* DO NOT DELETE THIS LINE -- stddef.h INSERTED HERE. */
+#ifndef _STDDEF_H
+#define _STDDEF_H
+
+/* Signed type of difference of two pointers. */
+
+typedef long ptrdiff_t;
+
+/* Unsigned type of `sizeof' something. */
+
+#ifndef _SIZE_T /* in case <sys/types.h> has defined it. */
+#define _SIZE_T
+typedef unsigned long size_t;
+#endif /* _SIZE_T */
+
+/* A null pointer constant. */
+
+#undef NULL /* in case <stdio.h> has defined it. */
+#define NULL 0
+
+/* Offset of member MEMBER in a struct of type TYPE. */
+
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+
+#endif /* _STDDEF_H */
+#endif
+
+/* DO NOT DELETE THIS LINE -- stdlib.h INSERTED HERE. */
+/* Fake stdlib.h supplying the stuff needed by malloc. */
+
+#ifndef __ONEFILE
+#include <stddef.h>
+#endif
+
+extern void EXFUN(abort, (void));
+extern void EXFUN(free, (PTR));
+extern PTR EXFUN(malloc, (size_t));
+extern PTR EXFUN(realloc, (PTR, size_t));
+
+/* DO NOT DELETE THIS LINE -- string.h INSERTED HERE. */
+/* Fake string.h supplying stuff used by malloc. */
+#ifndef __ONEFILE
+#include <stddef.h>
+#endif
+
+extern PTR EXFUN(memcpy, (PTR, PTR, size_t));
+extern PTR EXFUN(memset, (PTR, int, size_t));
+#define memmove memcpy
+
+#define _MALLOC_INTERNAL
+/* DO NOT DELETE THIS LINE -- malloc.h INSERTED HERE. */
+/* Declarations for `malloc' and friends.
+ Copyright 1990 Free Software Foundation
+ Written May 1989 by Mike Haertel.
+
+ 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author may be reached (Email) at the address mike@@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#ifndef _MALLOC_H
+
+#define _MALLOC_H 1
+
+#ifndef __ONEFILE
+#define __need_NULL
+#define __need_size_t
+#define __need_ptrdiff_t
+#include <stddef.h>
+#endif
+
+#ifdef _MALLOC_INTERNAL
+
+#ifndef __ONEFILE
+#include <limits.h>
+#endif
+
+/* The allocator divides the heap into blocks of fixed size; large
+ requests receive one or more whole blocks, and small requests
+ receive a fragment of a block. Fragment sizes are powers of two,
+ and all fragments of a block are the same size. When all the
+ fragments in a block have been freed, the block itself is freed. */
+#define INT_BIT (CHAR_BIT * sizeof(int))
+#define BLOCKLOG (INT_BIT > 16 ? 12 : 9)
+#define BLOCKSIZE (1 << BLOCKLOG)
+#define BLOCKIFY(SIZE) (((SIZE) + BLOCKSIZE - 1) / BLOCKSIZE)
+
+/* Determine the amount of memory spanned by the initial heap table
+ (not an absolute limit). */
+#define HEAP (INT_BIT > 16 ? 4194304 : 65536)
+
+/* Number of contiguous free blocks allowed to build up at the end of
+ memory before they will be returned to the system. */
+#define FINAL_FREE_BLOCKS 8
+
+/* Where to start searching the free list when looking for new memory.
+ The two possible values are 0 and _heapindex. Starting at 0 seems
+ to reduce total memory usage, while starting at _heapindex seems to
+ run faster. */
+#define MALLOC_SEARCH_START _heapindex
+
+/* Data structure giving per-block information. */
+typedef union
+ {
+ /* Heap information for a busy block. */
+ struct
+ {
+ /* Zero for a large block, or positive giving the
+ logarithm to the base two of the fragment size. */
+ int type;
+ union
+ {
+ struct
+ {
+ size_t nfree; /* Free fragments in a fragmented block. */
+ size_t first; /* First free fragment of the block. */
+ } frag;
+ /* Size (in blocks) of a large cluster. */
+ size_t size;
+ } info;
+ } busy;
+ /* Heap information for a free block (that may be the first of
+ a free cluster). */
+ struct
+ {
+ size_t size; /* Size (in blocks) of a free cluster. */
+ size_t next; /* Index of next free cluster. */
+ size_t prev; /* Index of previous free cluster. */
+ } free;
+ } malloc_info;
+
+/* Pointer to first block of the heap. */
+extern char *_heapbase;
+
+/* Table indexed by block number giving per-block information. */
+extern malloc_info *_heapinfo;
+
+/* Address to block number and vice versa. */
+#define BLOCK(A) (((char *) (A) - _heapbase) / BLOCKSIZE + 1)
+#define ADDRESS(B) ((PTR) (((B) - 1) * BLOCKSIZE + _heapbase))
+
+/* Current search index for the heap table. */
+extern size_t _heapindex;
+
+/* Limit of valid info table indices. */
+extern size_t _heaplimit;
+
+/* Doubly linked lists of free fragments. */
+struct list
+ {
+ struct list *next;
+ struct list *prev;
+ };
+
+/* Free list headers for each fragment size. */
+extern struct list _fraghead[];
+
+/* Instrumentation. */
+extern size_t _chunks_used;
+extern size_t _bytes_used;
+extern size_t _chunks_free;
+extern size_t _bytes_free;
+
+/* Internal version of free() used in morecore(). */
+extern void EXFUN(__free, (PTR __ptr));
+
+#endif /* _MALLOC_INTERNAL. */
+
+/* Underlying allocation function; successive calls should
+ return contiguous pieces of memory. */
+extern PTR EXFUN((*__morecore), (ptrdiff_t __size));
+
+/* Default value of previous. */
+extern PTR EXFUN(__default_morecore, (ptrdiff_t __size));
+
+/* Flag whether malloc has been called. */
+extern int __malloc_initialized;
+
+/* Hooks for debugging versions. */
+extern void EXFUN((*__free_hook), (PTR __ptr));
+extern PTR EXFUN((*__malloc_hook), (size_t __size));
+extern PTR EXFUN((*__realloc_hook), (PTR __ptr, size_t __size));
+
+/* Activate a standard collection of debugging hooks. */
+extern void EXFUN(mcheck, (void EXFUN((*func), (void))));
+
+/* Statistics available to the user. */
+struct mstats
+ {
+ size_t bytes_total; /* Total size of the heap. */
+ size_t chunks_used; /* Chunks allocated by the user. */
+ size_t bytes_used; /* Byte total of user-allocated chunks. */
+ size_t chunks_free; /* Chunks in the free list. */
+ size_t bytes_free; /* Byte total of chunks in the free list. */
+ };
+
+/* Pick up the current statistics. */
+extern struct mstats EXFUN(mstats, (NOARGS));
+
+#endif /* malloc.h */
+
+/* DO NOT DELETE THIS LINE -- free.c INSERTED HERE. */
+/* Free a block of memory allocated by `malloc'.
+ Copyright 1990 Free Software Foundation
+ Written May 1989 by Mike Haertel.
+
+ 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author may be reached (Email) at the address mike@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#ifndef __ONEFILE
+#include "ansidecl.h"
+#include <stddef.h>
+#include <stdlib.h>
+
+#define _MALLOC_INTERNAL
+#include "malloc.h"
+#endif /* __ONEFILE */
+
+/* Debugging hook for free. */
+void EXFUN((*__free_hook), (PTR __ptr));
+
+/* Return memory to the heap. Like free() but don't call a __free_hook
+ if there is one. */
+void
+DEFUN(__free, (ptr), PTR ptr)
+{
+ int type;
+ size_t block, blocks;
+ register size_t i;
+ struct list *prev, *next;
+
+ block = BLOCK(ptr);
+
+ type = _heapinfo[block].busy.type;
+ switch (type)
+ {
+ case 0:
+ /* Get as many statistics as early as we can. */
+ --_chunks_used;
+ _bytes_used -= _heapinfo[block].busy.info.size * BLOCKSIZE;
+ _bytes_free += _heapinfo[block].busy.info.size * BLOCKSIZE;
+
+ /* Find the free cluster previous to this one in the free list.
+ Start searching at the last block referenced; this may benefit
+ programs with locality of allocation. */
+ i = _heapindex;
+ if (i > block)
+ while (i > block)
+ i = _heapinfo[i].free.prev;
+ else
+ {
+ do
+ i = _heapinfo[i].free.next;
+ while (i > 0 && i < block);
+ i = _heapinfo[i].free.prev;
+ }
+
+ /* Determine how to link this block into the free list. */
+ if (block == i + _heapinfo[i].free.size)
+ {
+ /* Coalesce this block with its predecessor. */
+ _heapinfo[i].free.size += _heapinfo[block].busy.info.size;
+ block = i;
+ }
+ else
+ {
+ /* Really link this block back into the free list. */
+ _heapinfo[block].free.size = _heapinfo[block].busy.info.size;
+ _heapinfo[block].free.next = _heapinfo[i].free.next;
+ _heapinfo[block].free.prev = i;
+ _heapinfo[i].free.next = block;
+ _heapinfo[_heapinfo[block].free.next].free.prev = block;
+ ++_chunks_free;
+ }
+
+ /* Now that the block is linked in, see if we can coalesce it
+ with its successor (by deleting its successor from the list
+ and adding in its size). */
+ if (block + _heapinfo[block].free.size == _heapinfo[block].free.next)
+ {
+ _heapinfo[block].free.size
+ += _heapinfo[_heapinfo[block].free.next].free.size;
+ _heapinfo[block].free.next
+ = _heapinfo[_heapinfo[block].free.next].free.next;
+ _heapinfo[_heapinfo[block].free.next].free.prev = block;
+ --_chunks_free;
+ }
+
+ /* Now see if we can return stuff to the system. */
+ blocks = _heapinfo[block].free.size;
+ if (blocks >= FINAL_FREE_BLOCKS && block + blocks == _heaplimit
+ && (*__morecore)(0) == ADDRESS(block + blocks))
+ {
+ register size_t bytes = blocks * BLOCKSIZE;
+ _heaplimit -= blocks;
+ (*__morecore)(- bytes);
+ _heapinfo[_heapinfo[block].free.prev].free.next
+ = _heapinfo[block].free.next;
+ _heapinfo[_heapinfo[block].free.next].free.prev
+ = _heapinfo[block].free.prev;
+ block = _heapinfo[block].free.prev;
+ --_chunks_free;
+ _bytes_free -= bytes;
+ }
+
+ /* Set the next search to begin at this block. */
+ _heapindex = block;
+ break;
+
+ default:
+ /* Do some of the statistics. */
+ --_chunks_used;
+ _bytes_used -= 1 << type;
+ ++_chunks_free;
+ _bytes_free += 1 << type;
+
+ /* Get the address of the first free fragment in this block. */
+ prev = (struct list *) ((char *) ADDRESS(block) +
+ (_heapinfo[block].busy.info.frag.first << type));
+
+ if (_heapinfo[block].busy.info.frag.nfree == (BLOCKSIZE >> type) - 1)
+ {
+ /* If all fragments of this block are free, remove them
+ from the fragment list and free the whole block. */
+ next = prev;
+ for (i = 1; i < BLOCKSIZE >> type; ++i)
+ next = next->next;
+ prev->prev->next = next;
+ if (next != NULL)
+ next->prev = prev->prev;
+ _heapinfo[block].busy.type = 0;
+ _heapinfo[block].busy.info.size = 1;
+
+ /* Keep the statistics accurate. */
+ ++_chunks_used;
+ _bytes_used += BLOCKSIZE;
+ _chunks_free -= BLOCKSIZE >> type;
+ _bytes_free -= BLOCKSIZE;
+
+ free(ADDRESS(block));
+ }
+ else if (_heapinfo[block].busy.info.frag.nfree != 0)
+ {
+ /* If some fragments of this block are free, link this
+ fragment into the fragment list after the first free
+ fragment of this block. */
+ next = (struct list *) ptr;
+ next->next = prev->next;
+ next->prev = prev;
+ prev->next = next;
+ if (next->next != NULL)
+ next->next->prev = next;
+ ++_heapinfo[block].busy.info.frag.nfree;
+ }
+ else
+ {
+ /* No fragments of this block are free, so link this
+ fragment into the fragment list and announce that
+ it is the first free fragment of this block. */
+ prev = (struct list *) ptr;
+ _heapinfo[block].busy.info.frag.nfree = 1;
+ _heapinfo[block].busy.info.frag.first = (unsigned int)
+ (((char *) ptr - (char *) NULL) % BLOCKSIZE >> type);
+ prev->next = _fraghead[type].next;
+ prev->prev = &_fraghead[type];
+ prev->prev->next = prev;
+ if (prev->next != NULL)
+ prev->next->prev = prev;
+ }
+ break;
+ }
+}
+
+/* Return memory to the heap. */
+void
+DEFUN(free, (ptr), PTR ptr)
+{
+ if (ptr == NULL)
+ return;
+
+ if (__free_hook != NULL)
+ (*__free_hook)(ptr);
+ else
+ __free (ptr);
+}
+
+/* DO NOT DELETE THIS LINE -- malloc.c INSERTED HERE. */
+/* Memory allocator `malloc'.
+ Copyright 1990 Free Software Foundation
+ Written May 1989 by Mike Haertel.
+
+ 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author may be reached (Email) at the address mike@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#ifndef __ONEFILE
+#include "ansidecl.h"
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define _MALLOC_INTERNAL
+#include "malloc.h"
+#endif /* __ONEFILE */
+
+/* How to really get more memory. */
+PTR EXFUN((*__morecore), (ptrdiff_t __size)) = __default_morecore;
+
+/* Debugging hook for `malloc'. */
+PTR EXFUN((*__malloc_hook), (size_t __size));
+
+/* Pointer to the base of the first block. */
+char *_heapbase;
+
+/* Block information table. Allocated with align/__free (not malloc/free). */
+malloc_info *_heapinfo;
+
+/* Number of info entries. */
+static size_t heapsize;
+
+/* Search index in the info table. */
+size_t _heapindex;
+
+/* Limit of valid info table indices. */
+size_t _heaplimit;
+
+/* Free lists for each fragment size. */
+struct list _fraghead[BLOCKLOG];
+
+/* Instrumentation. */
+size_t _chunks_used;
+size_t _bytes_used;
+size_t _chunks_free;
+size_t _bytes_free;
+
+/* Are you experienced? */
+int __malloc_initialized;
+
+/* Aligned allocation. */
+static PTR
+DEFUN(align, (size), size_t size)
+{
+ PTR result;
+ unsigned int adj;
+
+ result = (*__morecore)(size);
+ adj = (unsigned int) ((char *) result - (char *) NULL) % BLOCKSIZE;
+ if (adj != 0)
+ {
+ adj = BLOCKSIZE - adj;
+ (void) (*__morecore)(adj);
+ result = (char *) result + adj;
+ }
+ return result;
+}
+
+/* Set everything up and remember that we have. */
+static int
+DEFUN_VOID(initialize)
+{
+ heapsize = HEAP / BLOCKSIZE;
+ _heapinfo = (malloc_info *) align(heapsize * sizeof(malloc_info));
+ if (_heapinfo == NULL)
+ return 0;
+ memset(_heapinfo, 0, heapsize * sizeof(malloc_info));
+ _heapinfo[0].free.size = 0;
+ _heapinfo[0].free.next = _heapinfo[0].free.prev = 0;
+ _heapindex = 0;
+ _heapbase = (char *) _heapinfo;
+ __malloc_initialized = 1;
+ return 1;
+}
+
+/* Get neatly aligned memory, initializing or
+ growing the heap info table as necessary. */
+static PTR
+DEFUN(morecore, (size), size_t size)
+{
+ PTR result;
+ malloc_info *newinfo, *oldinfo;
+ size_t newsize;
+
+ result = align(size);
+ if (result == NULL)
+ return NULL;
+
+ /* Check if we need to grow the info table. */
+ if (BLOCK((char *) result + size) > heapsize)
+ {
+ newsize = heapsize;
+ while (BLOCK((char *) result + size) > newsize)
+ newsize *= 2;
+ newinfo = (malloc_info *) align(newsize * sizeof(malloc_info));
+ if (newinfo == NULL)
+ {
+ (*__morecore)(- size);
+ return NULL;
+ }
+ memset(newinfo, 0, newsize * sizeof(malloc_info));
+ memcpy(newinfo, _heapinfo, heapsize * sizeof(malloc_info));
+ oldinfo = _heapinfo;
+ newinfo[BLOCK(oldinfo)].busy.type = 0;
+ newinfo[BLOCK(oldinfo)].busy.info.size
+ = BLOCKIFY(heapsize * sizeof(malloc_info));
+ _heapinfo = newinfo;
+ __free(oldinfo);
+ heapsize = newsize;
+ }
+
+ _heaplimit = BLOCK((char *) result + size);
+ return result;
+}
+
+/* Allocate memory from the heap. */
+PTR
+DEFUN(malloc, (size), size_t size)
+{
+ PTR result;
+ size_t block, blocks, lastblocks, start;
+ register size_t i;
+ struct list *next;
+
+ if (size == 0)
+ return NULL;
+
+ if (__malloc_hook != NULL)
+ return (*__malloc_hook)(size);
+
+ if (!__malloc_initialized)
+ if (!initialize())
+ return NULL;
+
+ if (size < sizeof(struct list))
+ size = sizeof(struct list);
+
+ /* Determine the allocation policy based on the request size. */
+ if (size <= BLOCKSIZE / 2)
+ {
+ /* Small allocation to receive a fragment of a block.
+ Determine the logarithm to base two of the fragment size. */
+ register size_t log = 1;
+ --size;
+ while ((size /= 2) != 0)
+ ++log;
+
+ /* Look in the fragment lists for a
+ free fragment of the desired size. */
+ next = _fraghead[log].next;
+ if (next != NULL)
+ {
+ /* There are free fragments of this size.
+ Pop a fragment out of the fragment list and return it.
+ Update the block's nfree and first counters. */
+ result = (PTR) next;
+ next->prev->next = next->next;
+ if (next->next != NULL)
+ next->next->prev = next->prev;
+ block = BLOCK(result);
+ if (--_heapinfo[block].busy.info.frag.nfree != 0)
+ _heapinfo[block].busy.info.frag.first = (unsigned int)
+ (((char *) next->next - (char *) NULL) % BLOCKSIZE) >> log;
+
+ /* Update the statistics. */
+ ++_chunks_used;
+ _bytes_used += 1 << log;
+ --_chunks_free;
+ _bytes_free -= 1 << log;
+ }
+ else
+ {
+ /* No free fragments of the desired size, so get a new block
+ and break it into fragments, returning the first. */
+ result = malloc(BLOCKSIZE);
+ if (result == NULL)
+ return NULL;
+
+ /* Link all fragments but the first into the free list. */
+ for (i = 1; i < BLOCKSIZE >> log; ++i)
+ {
+ next = (struct list *) ((char *) result + (i << log));
+ next->next = _fraghead[log].next;
+ next->prev = &_fraghead[log];
+ next->prev->next = next;
+ if (next->next != NULL)
+ next->next->prev = next;
+ }
+
+ /* Initialize the nfree and first counters for this block. */
+ block = BLOCK(result);
+ _heapinfo[block].busy.type = log;
+ _heapinfo[block].busy.info.frag.nfree = i - 1;
+ _heapinfo[block].busy.info.frag.first = i - 1;
+
+ _chunks_free += (BLOCKSIZE >> log) - 1;
+ _bytes_free += BLOCKSIZE - (1 << log);
+ }
+ }
+ else
+ {
+ /* Large allocation to receive one or more blocks.
+ Search the free list in a circle starting at the last place visited.
+ If we loop completely around without finding a large enough
+ space we will have to get more memory from the system. */
+ blocks = BLOCKIFY(size);
+ start = block = MALLOC_SEARCH_START;
+ while (_heapinfo[block].free.size < blocks)
+ {
+ block = _heapinfo[block].free.next;
+ if (block == start)
+ {
+ /* Need to get more from the system. Check to see if
+ the new core will be contiguous with the final free
+ block; if so we don't need to get as much. */
+ block = _heapinfo[0].free.prev;
+ lastblocks = _heapinfo[block].free.size;
+ if (_heaplimit != 0 && block + lastblocks == _heaplimit &&
+ (*__morecore)(0) == ADDRESS(block + lastblocks) &&
+ (morecore((blocks - lastblocks) * BLOCKSIZE)) != NULL)
+ {
+ _heapinfo[block].free.size = blocks;
+ _bytes_free += (blocks - lastblocks) * BLOCKSIZE;
+ continue;
+ }
+ result = morecore(blocks * BLOCKSIZE);
+ if (result == NULL)
+ return NULL;
+ block = BLOCK(result);
+ _heapinfo[block].busy.type = 0;
+ _heapinfo[block].busy.info.size = blocks;
+ ++_chunks_used;
+ _bytes_used += blocks * BLOCKSIZE;
+ return result;
+ }
+ }
+
+ /* At this point we have found a suitable free list entry.
+ Figure out how to remove what we need from the list. */
+ result = ADDRESS(block);
+ if (_heapinfo[block].free.size > blocks)
+ {
+ /* The block we found has a bit left over,
+ so relink the tail end back into the free list. */
+ _heapinfo[block + blocks].free.size
+ = _heapinfo[block].free.size - blocks;
+ _heapinfo[block + blocks].free.next
+ = _heapinfo[block].free.next;
+ _heapinfo[block + blocks].free.prev
+ = _heapinfo[block].free.prev;
+ _heapinfo[_heapinfo[block].free.prev].free.next
+ = _heapinfo[_heapinfo[block].free.next].free.prev
+ = _heapindex = block + blocks;
+ }
+ else
+ {
+ /* The block exactly matches our requirements,
+ so just remove it from the list. */
+ _heapinfo[_heapinfo[block].free.next].free.prev
+ = _heapinfo[block].free.prev;
+ _heapinfo[_heapinfo[block].free.prev].free.next
+ = _heapindex = _heapinfo[block].free.next;
+ --_chunks_free;
+ }
+
+ _heapinfo[block].busy.type = 0;
+ _heapinfo[block].busy.info.size = blocks;
+ ++_chunks_used;
+ _bytes_used += blocks * BLOCKSIZE;
+ _bytes_free -= blocks * BLOCKSIZE;
+ }
+
+ return result;
+}
+
+/* DO NOT DELETE THIS LINE -- realloc.c INSERTED HERE. */
+/* Change the size of a block allocated by `malloc'.
+ Copyright 1990 Free Software Foundation
+ Written May 1989 by Mike Haertel.
+
+ 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author may be reached (Email) at the address mike@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#ifndef __ONEFILE
+#include "ansidecl.h"
+#include <stdlib.h>
+#include <string.h>
+
+#define _MALLOC_INTERNAL
+#include "malloc.h"
+#endif /* __ONEFILE */
+
+#define MIN(A, B) ((A) < (B) ? (A) : (B))
+
+/* Debugging hook for realloc. */
+PTR EXFUN((*__realloc_hook), (PTR __ptr, size_t __size));
+
+/* Resize the given region to the new size, returning a pointer
+ to the (possibly moved) region. This is optimized for speed;
+ some benchmarks seem to indicate that greater compactness is
+ achieved by unconditionally allocating and copying to a
+ new region. This module has incestuous knowledge of the
+ internals of both free and malloc. */
+PTR
+DEFUN(realloc, (ptr, size), PTR ptr AND size_t size)
+{
+ PTR result;
+ int type;
+ size_t block, blocks, oldlimit;
+
+ if (size == 0)
+ {
+ free(ptr);
+ return NULL;
+ }
+ else if (ptr == NULL)
+ return malloc(size);
+
+ if (__realloc_hook != NULL)
+ return (*__realloc_hook)(ptr, size);
+
+ block = BLOCK(ptr);
+
+ type = _heapinfo[block].busy.type;
+ switch (type)
+ {
+ case 0:
+ /* Maybe reallocate a large block to a small fragment. */
+ if (size <= BLOCKSIZE / 2)
+ {
+ result = malloc(size);
+ if (result != NULL)
+ {
+ memcpy(result, ptr, size);
+ free(ptr);
+ return result;
+ }
+ }
+
+ /* The new size is a large allocation as well;
+ see if we can hold it in place. */
+ blocks = BLOCKIFY(size);
+ if (blocks < _heapinfo[block].busy.info.size)
+ {
+ /* The new size is smaller; return
+ excess memory to the free list. */
+ _heapinfo[block + blocks].busy.type = 0;
+ _heapinfo[block + blocks].busy.info.size
+ = _heapinfo[block].busy.info.size - blocks;
+ _heapinfo[block].busy.info.size = blocks;
+ free(ADDRESS(block + blocks));
+ result = ptr;
+ }
+ else if (blocks == _heapinfo[block].busy.info.size)
+ /* No size change necessary. */
+ result = ptr;
+ else
+ {
+ /* Won't fit, so allocate a new region that will.
+ Free the old region first in case there is sufficient
+ adjacent free space to grow without moving. */
+ blocks = _heapinfo[block].busy.info.size;
+ /* Prevent free from actually returning memory to the system. */
+ oldlimit = _heaplimit;
+ _heaplimit = 0;
+ free(ptr);
+ _heaplimit = oldlimit;
+ result = malloc(size);
+ if (result == NULL)
+ {
+ (void) malloc(blocks * BLOCKSIZE);
+ return NULL;
+ }
+ if (ptr != result)
+ memmove(result, ptr, blocks * BLOCKSIZE);
+ }
+ break;
+
+ default:
+ /* Old size is a fragment; type is logarithm
+ to base two of the fragment size. */
+ if (size > 1 << (type - 1) && size <= 1 << type)
+ /* The new size is the same kind of fragment. */
+ result = ptr;
+ else
+ {
+ /* The new size is different; allocate a new space,
+ and copy the lesser of the new size and the old. */
+ result = malloc(size);
+ if (result == NULL)
+ return NULL;
+ memcpy(result, ptr, MIN(size, 1 << type));
+ free(ptr);
+ }
+ break;
+ }
+
+ return result;
+}
+
+/* DO NOT DELETE THIS LINE -- unix.c INSERTED HERE. */
+/* unix.c - get more memory with a UNIX system call.
+ Copyright 1990 Free Software Foundation
+ Written May 1989 by Mike Haertel.
+
+ 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author may be reached (Email) at the address mike@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#ifndef __ONEFILE
+#include "ansidecl.h"
+#include <stddef.h>
+
+#define _MALLOC_INTERNAL
+#include "malloc.h"
+#endif /* __ONEFILE */
+
+extern PTR EXFUN(sbrk, (ptrdiff_t size));
+
+PTR
+DEFUN(__default_morecore, (size), ptrdiff_t size)
+{
+ PTR result;
+
+ result = sbrk(size);
+ if (result == (PTR) -1)
+ return NULL;
+ return result;
+}
+
+#define __getpagesize getpagesize
+/* DO NOT DELETE THIS LINE -- valloc.c INSERTED HERE. */
+/* Allocate memory on a page boundary.
+ Copyright 1990 Free Software Foundation
+ Written May 1989 by Mike Haertel.
+
+ 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ The author may be reached (Email) at the address mike@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#ifndef __ONEFILE
+#include "ansidecl.h"
+#include <stdlib.h>
+#endif /* __ONEFILE */
+
+extern size_t EXFUN(__getpagesize, (NOARGS));
+
+static size_t pagesize;
+
+PTR
+DEFUN(valloc, (size), size_t size)
+{
+ PTR result;
+ unsigned int adj;
+
+ if (pagesize == 0)
+ pagesize = __getpagesize();
+
+ result = malloc(size + pagesize);
+ if (result == NULL)
+ return NULL;
+ adj = (unsigned int) ((char *) result - (char *) NULL) % pagesize;
+ if (adj != 0)
+ result = (char *) result + pagesize - adj;
+ return result;
+}
diff --git a/binutils/m68k-pinsn.c b/binutils/m68k-pinsn.c
index 284f335..b84a869 100644
--- a/binutils/m68k-pinsn.c
+++ b/binutils/m68k-pinsn.c
@@ -20,9 +20,12 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* $Id$
$Log$
- Revision 1.1 1991/03/21 21:26:45 gumby
- Initial revision
+ Revision 1.1.1.1 1991/03/21 21:26:46 gumby
+ Back from Intel with Steve
+ * Revision 1.1 1991/03/21 21:26:45 gumby
+ * Initial revision
+ *
* Revision 1.1 1991/03/13 00:34:06 chrisb
* Initial revision
*
diff --git a/binutils/ostrip.c b/binutils/ostrip.c
new file mode 100755
index 0000000..6ba318c
--- /dev/null
+++ b/binutils/ostrip.c
@@ -0,0 +1,418 @@
+/* strip certain symbols from a rel file.
+ Copyright (C) 1986, 1990 Free Software Foundation, Inc.
+
+ 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "sysdep.h"
+
+#include <stdio.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "getopt.h"
+#include "bfd.h"
+
+enum strip_action {
+ strip_undef,
+ strip_all, /* strip all symbols */
+ strip_debug, /* strip all debugger symbols */
+};
+
+/* Which symbols to remove. */
+enum strip_action strip_symbols;
+
+enum locals_action {
+ locals_undef,
+ locals_start_L, /* discard locals starting with L */
+ locals_all, /* discard all locals */
+};
+
+/* Which local symbols to remove. */
+enum locals_action discard_locals;
+
+/* The name this program was run with. */
+char *program_name;
+
+struct option long_options[] = {
+ {"strip-all", 0, 0, 's'},
+ {"strip-debug", 0, 0, 'S'},
+ {"discard-all", 0, 0, 'x'},
+ {"discard-locals", 0, 0, 'X'},
+ {0, 0, 0, 0},
+};
+
+static char *target = NULL;
+
+static int fatal_error;
+
+extern char *malloc();
+extern char *mktemp();
+extern char *realloc();
+extern char *strcpy();
+extern int exit();
+extern int fprintf();
+extern int free();
+extern int getpid();
+extern int kill();
+extern int perror();
+extern int sprintf();
+extern int unlink();
+
+#ifdef __STDC__
+static int strip_bfd(bfd *ibfd, bfd *obfd);
+static int strip_file(char *filetostrip);
+static void usage(void);
+#else
+static int strip_bfd();
+static int strip_file();
+static void usage();
+#endif /* __STDC__ */
+static void copy_sections ();
+static void setup_sections ();
+
+int main(argc, argv)
+char **argv;
+int argc;
+{
+ int ind;
+ int c;
+ program_name = argv[0];
+
+ strip_symbols = strip_undef; /* default is to strip everything. */
+ discard_locals = locals_undef;
+
+ while ((c = getopt_long (argc, argv, "gsST:xX", long_options, &ind)) != EOF) {
+ switch (c) {
+ case 0:
+ break;
+ case 's':
+ strip_symbols = strip_all;
+ break;
+ case 'g':
+ case 'S':
+ strip_symbols = strip_debug;
+ break;
+ case 'T':
+ target = optarg;
+ break;
+ case 'x':
+ discard_locals = locals_all;
+ break;
+ case 'X':
+ discard_locals = locals_start_L;
+ break;
+ default:
+ usage ();
+ } /* switch on option */
+ } /* for each option */
+
+ if (strip_symbols == strip_undef && discard_locals == locals_undef) {
+ strip_symbols = strip_all;
+ } /* Default is to strip all symbols. */
+
+
+ if (argc == optind) {
+ return(strip_file("a.out"));
+ } else {
+ int retval = 0;
+
+ for ( ; optind < argc; ++optind) {
+ retval &= strip_file(argv[optind]);
+ } /* for each file to strip */
+
+ return(retval);
+ } /* if no arguments given */
+
+} /* main() */
+
+static int delayed_signal;
+
+void delay_signal(signo)
+int signo;
+{
+ delayed_signal = signo;
+ signal(signo, delay_signal);
+} /* delay_signal() */
+
+static int sigint_handled = 0;
+static int sighup_handled = 0;
+static int sigterm_handled = 0;
+
+void handle_sigs() {
+ /* Effectively defer handling of asynchronous kill signals. */
+ delayed_signal = 0;
+
+ if (signal (SIGINT, SIG_IGN) != SIG_IGN) {
+ sigint_handled = 1;
+ signal(SIGINT, delay_signal);
+ } /* if not ignored */
+
+ if (signal (SIGHUP, SIG_IGN) != SIG_IGN) {
+ sighup_handled = 1;
+ signal(SIGHUP, delay_signal);
+ } /* if not ignored */
+
+ if (signal (SIGTERM, SIG_IGN) != SIG_IGN) {
+ sigterm_handled = 1;
+ signal(SIGTERM, delay_signal);
+ } /* if not ignored */
+
+ return;
+} /* handle_sigs() */
+
+void unhandle_sigs() {
+ /* Effectively undefer handling. */
+ if (sigint_handled)
+ signal (SIGINT, SIG_DFL);
+ if (sighup_handled)
+ signal (SIGHUP, SIG_DFL);
+ if (sigterm_handled)
+ signal (SIGTERM, SIG_DFL);
+
+ /* Handle any signal that came in while they were deferred. */
+ if (delayed_signal)
+ kill (getpid (), delayed_signal);
+
+ return;
+} /* unhandle_sigs() */
+
+static int strip_file(filetostrip)
+char *filetostrip;
+{
+ bfd *ibfd;
+ bfd *obfd;
+ char tmpfilename[] = "stXXXXXX";
+
+ if ((ibfd = bfd_openr(filetostrip, (char *)NULL)) == NULL) {
+ bfd_perror(filetostrip);
+ return(1);
+ } /* on error opening input */
+
+ obfd = bfd_openw(mktemp(tmpfilename),
+ target? target: bfd_get_target (ibfd));
+ if (obfd == NULL) {
+ bfd_perror(tmpfilename);
+
+ if (bfd_close(ibfd) == false) {
+ bfd_perror(bfd_get_filename(ibfd));
+ } /* on close error */
+
+ return(1);
+ } /* on error opening output */
+
+ handle_sigs();
+
+ if (bfd_check_format(ibfd, bfd_object) != false) {
+ if (bfd_set_format(obfd, bfd_get_format(ibfd)) != false) {
+ if (!strip_bfd(ibfd, obfd)) {
+ /* success */
+
+ if (bfd_close(ibfd) == false) {
+ bfd_perror(bfd_get_filename(ibfd));
+ } /* on close error */
+
+ if (bfd_close(obfd) == false) {
+ bfd_perror(bfd_get_filename(obfd));
+ } /* on close error */
+
+ rename(tmpfilename, filetostrip);
+ unhandle_sigs();
+ return(0);
+ } /* strip_bfd prints it's own failing messages */
+ } else {
+ bfd_perror(filetostrip);
+ } /* can't set format */
+ } else {
+ /* not an object file */
+ (void) fprintf(stderr, "File %s has format 0x%x that will not be stripped.\n",
+ filetostrip, (unsigned) bfd_get_format(ibfd));
+ } /* if anything fails along the way */
+
+
+ if (bfd_close(ibfd) == false) {
+ bfd_perror(bfd_get_filename(ibfd));
+ } /* on close error */
+
+ if (bfd_close(obfd) == false) {
+ bfd_perror(bfd_get_filename(obfd));
+ } /* on close error */
+
+ if (unlink(tmpfilename)) {
+ perror(tmpfilename);
+ } /* on error */
+
+ unhandle_sigs();
+
+ return(1);
+} /* strip_file() */
+
+
+boolean
+bfd_set_start_address (abfd, new_address)
+ bfd *abfd;
+ bfd_vma new_address;
+{
+ bfd_get_start_address (abfd) = new_address;
+ return true;
+}
+
+
+
+static int
+strip_bfd(ibfd, obfd)
+ bfd *ibfd;
+ bfd *obfd;
+{
+ if (bfd_set_start_address(obfd, bfd_get_start_address(ibfd)) == false
+ || bfd_set_file_flags(obfd, bfd_get_file_flags(ibfd) & ~(HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS)) == false
+ || bfd_set_start_address(obfd, bfd_get_start_address(ibfd)) == false) {
+ bfd_perror(bfd_get_filename(ibfd));
+ return(1);
+ } /* on error setting file attributes */
+
+ /* bfd mandates that all output sections be created and sizes set before
+ any output is done. Thus, we traverse all sections twice. */
+
+ fatal_error = 0;
+ bfd_map_over_sections (ibfd, setup_sections, (void *)obfd);
+ if (!fatal_error)
+ bfd_map_over_sections (ibfd, copy_sections, (void *)obfd);
+ return fatal_error;
+}
+
+static void
+setup_sections(ibfd, isection, obfd)
+bfd *ibfd;
+sec_ptr isection;
+bfd *obfd;
+{
+ sec_ptr osection;
+ char *err;
+
+ do {
+ err = "making";
+ osection = bfd_make_section(obfd, bfd_section_name(ibfd, isection));
+ if (osection == NULL)
+ break;
+ err = "size";
+ if (!bfd_set_section_size(obfd, osection,
+ bfd_section_size(ibfd, isection)))
+ break;
+ err = "vma";
+ if (!bfd_set_section_vma(obfd, osection,
+ bfd_section_vma(ibfd, isection)))
+ break;
+ err = "alignment";
+ if (!bfd_set_section_alignment(obfd, osection,
+ bfd_section_alignment(ibfd, isection)))
+ break;
+ err = "flags";
+ if (!bfd_set_section_flags(obfd, osection,
+ bfd_get_section_flags(ibfd, isection)))
+ break;
+ return;
+ } while (0);
+
+ (void) fprintf(stderr, "file \"%s\", section \"%s\": error in %s: ",
+ bfd_get_filename(ibfd),
+ bfd_section_name(ibfd, isection),
+ err);
+
+ bfd_perror("");
+ fatal_error = 1;
+}
+
+static void
+copy_sections(ibfd, isection, obfd)
+bfd *ibfd;
+sec_ptr isection;
+bfd *obfd;
+{
+ static char *memhunk = NULL;
+ static unsigned memhunksize = 0;
+
+ sec_ptr osection;
+ unsigned long size;
+ flagword iflg;
+ char *temp;
+
+ osection = bfd_get_section_by_name (obfd,
+ bfd_section_name(ibfd, isection));
+
+ size = bfd_section_size(ibfd, isection);
+ iflg = bfd_get_section_flags(ibfd, isection);
+
+ /* either:
+ we don't need any memory because there's nothing in this section,
+ we had no memory so we got some,
+ we had some memory but not enough so we got more,
+ or we fail to allocat. */
+
+ if (size == 0)
+ return;
+
+ if (memhunk == NULL) {
+ memhunk = malloc (size);
+ memhunksize = size;
+ }
+
+ if (size > memhunksize) {
+ temp = realloc (memhunk, size);
+ memhunksize = size;
+ if (!temp) /* If realloc failed, blow away our mem */
+ free (memhunk);
+ memhunk = temp;
+ }
+
+ if (memhunk == NULL) {
+ /* failed to allocate or reallocate */
+ /* FIXME, we should just copy in pieces. */
+ (void) fprintf(stderr,
+ "Could not allocate %lu bytes in which to copy section.\n", size);
+ return;
+ }
+
+ /* now we have enough memory */
+
+ if (!bfd_get_section_contents(ibfd, isection, memhunk, 0, size)) {
+ bfd_perror(bfd_get_filename(ibfd));
+ fatal_error = 1;
+ return;
+ }
+ if (!bfd_set_section_contents(obfd, osection, memhunk, 0, size)) {
+ bfd_perror(bfd_get_filename(obfd));
+ fatal_error = 1;
+ return;
+ }
+}
+
+void
+usage ()
+{
+ fprintf (stderr, "\
+Usage: %s [-gsxSX] [+strip-all] [+strip-debug] [+discard-all]\n\
+ [+discard-locals] file...\n", program_name);
+ exit (1);
+}
+
+/*
+ * Local Variables:
+ * comment-column: 0
+ * fill-column: 131
+ * End:
+ */
+
+/* end of strip.c */
diff --git a/binutils/sparc-pinsn.c b/binutils/sparc-pinsn.c
index 550722b..041cade 100644
--- a/binutils/sparc-pinsn.c
+++ b/binutils/sparc-pinsn.c
@@ -20,9 +20,12 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* $Id$
$Log$
- Revision 1.1 1991/03/21 21:26:55 gumby
- Initial revision
+ Revision 1.1.1.1 1991/03/21 21:26:56 gumby
+ Back from Intel with Steve
+ * Revision 1.1 1991/03/21 21:26:55 gumby
+ * Initial revision
+ *
* Revision 1.1 1991/03/13 00:34:40 chrisb
* Initial revision
*
diff --git a/binutils/strip.c b/binutils/strip.c
new file mode 100755
index 0000000..cd0f3af
--- /dev/null
+++ b/binutils/strip.c
@@ -0,0 +1,364 @@
+/*** strip.c -- strip certain symbols from a rel file.
+ Copyright (C) 1986, 1990 Free Software Foundation, Inc.
+
+ 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* BUGS: When there's not enough memory, this should do the copy
+ in pieces rather than just fail as it does now */
+
+#include "sysdep.h"
+#include "bfd.h"
+
+#include "getopt.h"
+
+
+
+#include <signal.h>
+
+/* Various program options */
+
+int show_version = 0;
+
+/* Which symbols to remove. */
+enum strip_action {
+ strip_undef,
+ strip_all, /* strip all symbols */
+ strip_debug, /* strip all debugger symbols */
+} strip_symbols;
+
+/* Which local symbols to remove. */
+enum {
+ locals_undef,
+ locals_start_L, /* discard locals starting with L */
+ locals_all, /* discard all locals */
+} discard_locals;
+
+extern char *mktemp();
+
+/* IMPORTS */
+extern char *program_version;
+extern char *program_name;
+extern char *target;
+extern char *xmalloc();
+
+PROTO(static boolean, strip_file, (char *filetostrip));
+PROTO(static void, copy_sections, (bfd *ibfd, sec_ptr isection, bfd *obfd));
+PROTO(static void, setup_sections, (bfd *ibfd, sec_ptr isection, bfd *obfd));
+
+/** main, etc */
+
+static void
+usage ()
+{
+ fprintf (stderr, "strip %s\nUsage: %s [-gsxSX] files ...\n",
+ program_version, program_name);
+ exit (1);
+}
+
+struct option long_options[] = {{"strip-all", 0, 0, 's'},
+ {"strip-debug", 0, 0, 'S'},
+ {"discard-all", 0, 0, 'x'},
+ {"discard-locals", 0, 0, 'X'},
+ {0, 0, 0, 0}
+ };
+
+int
+main (argc, argv)
+ char **argv;
+ int argc;
+{
+ int ind;
+ int c;
+ program_name = argv[0];
+
+ strip_symbols = strip_undef; /* default is to strip everything. */
+ discard_locals = locals_undef;
+
+ while ((c = getopt_long (argc, argv, "gsST:xX", long_options, &ind)) != EOF) {
+ switch (c) {
+ case 0:
+ break;
+ case 's':
+ strip_symbols = strip_all;
+ break;
+ case 'g':
+ case 'S':
+ strip_symbols = strip_debug;
+ break;
+ case 'T':
+ target = optarg;
+ break;
+ case 'x':
+ discard_locals = locals_all;
+ break;
+ case 'X':
+ discard_locals = locals_start_L;
+ break;
+ default:
+ usage ();
+ }
+ }
+
+ /* Default is to strip all symbols: */
+ if (strip_symbols == strip_undef && discard_locals == locals_undef) {
+ strip_symbols = strip_all;
+ }
+
+ /* OK, all options now parsed. If no filename specified, do a.out. */
+ if (optind == argc) return !strip_file ("a.out");
+
+ /* We were given several filenames to do: */
+ while (optind < argc)
+ if (!strip_file (argv[optind++])) return 1;
+
+ return 0;
+}
+
+/** Hack signals */
+
+/* Why does strip need to do this, and anyway, if it does shouldn't this be
+ handled by bfd? */
+
+static int delayed_signal;
+
+static int sigint_handled = 0;
+static int sighup_handled = 0;
+static int sigterm_handled = 0;
+
+void
+delay_signal (signo)
+ int signo;
+{
+ delayed_signal = signo;
+ signal (signo, delay_signal);
+}
+
+/* Effectively defer handling of asynchronous kill signals. */
+void
+handle_sigs () /* puff puff */
+{
+ delayed_signal = 0;
+
+ if (signal (SIGINT, SIG_IGN) != SIG_IGN) {
+ sigint_handled = 1;
+ signal (SIGINT, delay_signal);
+ }
+
+ if (signal (SIGHUP, SIG_IGN) != SIG_IGN) {
+ sighup_handled = 1;
+ signal (SIGHUP, delay_signal);
+ }
+
+ if (signal (SIGTERM, SIG_IGN) != SIG_IGN) {
+ sigterm_handled = 1;
+ signal (SIGTERM, delay_signal);
+ }
+
+ return;
+}
+
+/* Effectively undefer handling. */
+void
+unhandle_sigs () /* put them down */
+{
+ if (sigint_handled) signal (SIGINT, SIG_DFL);
+
+ if (sighup_handled) signal (SIGHUP, SIG_DFL);
+
+ if (sigterm_handled) signal (SIGTERM, SIG_DFL);
+
+ /* Handle any signal that came in while they were deferred. */
+ if (delayed_signal)
+ kill (getpid (), delayed_signal);
+
+ return;
+}
+
+
+static boolean
+strip_file (filetostrip)
+ char *filetostrip;
+{
+ static char template[] = "stXXXXXX";
+ char *slash;
+ char *tmpname;
+ bfd *ibfd;
+ bfd *obfd;
+
+ ibfd = bfd_openr (filetostrip, target);
+
+ if (ibfd == NULL) bfd_fatal (filetostrip);
+
+ handle_sigs (); /* light up */
+
+ if (!bfd_check_format (ibfd, bfd_object)) {
+ fprintf (stderr, "Can't strip %s file %s.\n",
+ bfd_format_string (bfd_get_format (ibfd)), filetostrip);
+ exit (1);
+ }
+
+ slash = strrchr( filetostrip, '/' );
+ if ( slash ){
+ *slash = 0;
+ tmpname = xmalloc( strlen(filetostrip) + sizeof(template) + 1 );
+ strcpy( tmpname, filetostrip );
+ strcat( tmpname, "/" );
+ strcat( tmpname, template );
+ mktemp( tmpname );
+ *slash = '/';
+ } else {
+ tmpname = xmalloc( sizeof(template) );
+ strcpy( tmpname, template );
+ mktemp( tmpname );
+ }
+
+ obfd = bfd_openw (mktemp(tmpname), (target ? target : bfd_get_target (ibfd)));
+ if (obfd == NULL) bfd_fatal (tmpname);
+
+ if (!bfd_set_format (obfd, bfd_get_format (ibfd)))
+ bfd_fatal (tmpname);
+
+
+ if ((bfd_set_start_address (obfd, bfd_get_start_address (ibfd)) == false) ||
+ (bfd_set_file_flags (obfd, (bfd_get_file_flags (ibfd) &
+ ~(HAS_LINENO | HAS_DEBUG | HAS_SYMS |
+ HAS_LOCALS))) == false) ||
+ bfd_set_start_address (obfd, bfd_get_start_address (ibfd)) == false)
+ bfd_fatal (bfd_get_filename (ibfd));
+
+ /* Copy architecture of input file to output file */
+ if (!bfd_set_arch_mach (obfd, bfd_get_architecture (ibfd),
+ bfd_get_machine (ibfd))) {
+ fprintf(stderr, "Output file cannot represent architecture %s",
+ bfd_printable_arch_mach (bfd_get_architecture(ibfd),
+ bfd_get_machine (ibfd)));
+ }
+
+
+ /* bfd mandates that all output sections be created and sizes set before
+ any output is done. Thus, we traverse all sections twice. */
+ bfd_map_over_sections (ibfd, setup_sections, (void *)obfd);
+ bfd_map_over_sections (ibfd, copy_sections, (void *)obfd);
+
+ if (!bfd_close (obfd)) bfd_fatal (filetostrip);
+ if (!bfd_close (ibfd)) bfd_fatal (filetostrip);
+
+ rename(tmpname, filetostrip);
+ free(tmpname);
+
+ unhandle_sigs();
+
+ return true;
+}
+
+/** Actually do the work */
+static void
+setup_sections (ibfd, isection, obfd)
+ bfd *ibfd;
+ sec_ptr isection;
+ bfd *obfd;
+{
+ sec_ptr osection;
+ char *err;
+
+ osection = bfd_make_section (obfd, bfd_section_name (ibfd, isection));
+ if (osection == NULL) {
+ err = "making";
+ goto loser;
+ }
+
+ if (!bfd_set_section_size(obfd, osection, bfd_section_size(ibfd, isection))) {
+ err = "size";
+ goto loser;
+ }
+
+ if (!bfd_set_section_vma (obfd, osection, bfd_section_vma (ibfd, isection))) {
+ err = "vma";
+ goto loser;
+ }
+
+ if (bfd_set_section_alignment (obfd, osection,
+ bfd_section_alignment (ibfd, isection))
+ != true) {
+ err = "alignment";
+ goto loser;
+ } /* on error, I presume. */
+
+ if (!bfd_set_section_flags (obfd, osection,
+ bfd_get_section_flags (ibfd, isection))) {
+ err = "flags";
+ goto loser;
+ }
+
+ /* All went well */
+ return;
+
+ loser:
+ fprintf (stderr, "%s: file \"%s\", section \"%s\": error in %s: %s\n",
+ program_name,
+ bfd_get_filename (ibfd), bfd_section_name (ibfd, isection),
+ err, bfd_errmsg (bfd_error));
+ exit (1);
+}
+
+static void
+copy_sections (ibfd, isection, obfd)
+ bfd *ibfd;
+ sec_ptr isection;
+ bfd *obfd;
+{
+ static unsigned char *memhunk = NULL;
+ static unsigned memhunksize = 0;
+
+ sec_ptr osection;
+ unsigned long size;
+ flagword iflg;
+ unsigned char *temp;
+
+ osection = bfd_get_section_by_name (obfd, bfd_section_name (ibfd, isection));
+
+ size = bfd_section_size (ibfd, isection);
+ iflg = bfd_get_section_flags (ibfd, isection);
+
+ /* either:
+ we don't need any memory because there's nothing in this section,
+ we had no memory so we got some,
+ we had some memory but not enough so we got more,
+ or we fail to allocat. */
+
+ if (size == 0)
+ return;
+
+ if ((iflg & SEC_HAS_CONTENTS) == 0)
+ return;
+
+ if (memhunk == NULL) {
+ memhunk = (unsigned char *) xmalloc (size);
+ memhunksize = size;
+ }
+
+ if (size > memhunksize) {
+ temp = (unsigned char *) xrealloc ((char *) memhunk, size);
+ memhunksize = size;
+ memhunk = temp;
+ }
+
+ /* now we have enough memory, just do it: */
+ if (!bfd_get_section_contents (ibfd, isection, memhunk, 0, size))
+ bfd_fatal (bfd_get_filename (ibfd));
+
+ if (!bfd_set_section_contents (obfd, osection, memhunk, 0, size))
+ bfd_fatal (bfd_get_filename (obfd));
+}