Back from Intel with Steve
authorDavid Henkel-Wallace <gumby@cygnus>
Thu, 21 Mar 1991 21:11:26 +0000 (21:11 +0000)
committerDavid Henkel-Wallace <gumby@cygnus>
Thu, 21 Mar 1991 21:11:26 +0000 (21:11 +0000)
bfd/VERSION [new file with mode: 0644]
bfd/aout.c
bfd/bfd.doc [new file with mode: 0755]
bfd/cplus-dem.c [new file with mode: 0755]
bfd/filemode.c [new file with mode: 0644]

diff --git a/bfd/VERSION b/bfd/VERSION
new file mode 100644 (file)
index 0000000..ba66466
--- /dev/null
@@ -0,0 +1 @@
+0.0
index f857897819e2c0e434e0cbe302d1ef52f33f04f0..9c3e1d8807bb79d4790c623a485ff71f44c0dd7d 100755 (executable)
@@ -20,7 +20,10 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 /* $Id$
  * $Log$
- * Revision 1.1  1991/03/21 21:11:23  gumby
+ * Revision 1.1.1.1  1991/03/21 21:11:23  gumby
+ * Back from Intel with Steve
+ *
+ * Revision 1.1  1991/03/21  21:11:23  gumby
  * Initial revision
  *
  * Revision 1.2  1991/03/15  18:16:52  rich
diff --git a/bfd/bfd.doc b/bfd/bfd.doc
new file mode 100755 (executable)
index 0000000..3e3183e
--- /dev/null
@@ -0,0 +1,705 @@
+This file contains -*- Text -*-.
+
+BFD is a set of routines for reading and writing binary files.
+
+The user should call only the interface routines at the end of bfd.h.
+The one I'm working out of is /4/gumby/bfd/bfd.h
+
+       Sample "strip" program using BFD:
+
+       #include "bfd.h"
+
+       doit ()
+       {
+               ibfd = bfd_openr(...)
+               obfd = bfd_openw(...)
+               bfd_check_format (ibfd, object);
+               bfd_set_format (obfd, object);
+
+               bfd_set_arch_mach (obfd, ...)
+               bfd_set_start_address (obfd, ...)
+               etc...
+       
+               [optionally:
+                 asymbol * foo = malloc (get_symtab_upper_bound (ibfd));
+                 bfd_canonicalize_symtab (ibfd, foo);
+                 <sort foo, frob foo, etc, using asymbol def from bfd.h>
+                 bfd_set_symtab (obfd, foo, updated_symbol_count);
+               ]
+
+               bfd_map_over_sections (abfd, setup, NULL);
+               bfd_map_over_sections (abfd, cleaner, NULL);
+
+               bfd_close (obfd);
+               bfd_close (ibfd);
+       }
+
+       setup (ibfd, sect)
+       {
+           osect = make_section (obfd, bfd_section_name (ibfd, sect));
+           bfd_set_section_size (obfd, osect, bfd_section_size (ibfd, sect));
+           ...     
+       }
+
+       cleaner (ibfd, sect)
+       {
+           osect = bfd_get_section_by_name (obfd,
+                                          bfd_section_name (ibfd, sect));
+           bfd_copy_section (ibfd, sect, obfd, osect);
+           [perhaps: bfd_set_reloc (osect, NULL, 0); ]
+       }
+           
+
+\f
+BFD is a package for manipulating binary files required for developing
+programs.  It implements a group of structured operations designed to
+shield the programmer from the underlying representation of these
+binary files.  It understands object (compiled) files, archive
+libraries, and core files.  It is designed to work in a variety of
+target environments.
+
+To use the library, include bfd.h and link with libbfd.a.      
+
+A bfd iteself is a representation for a particular file.  It is opened
+in a manner similar to a file; code then manipulates it rather than
+the raw files.
+\f
+BFD makes a distinction between TARGETS (families of file formats) and
+FORMATS (individual file formats).  For instance, the "sun4os4" target
+can handle core, object and archive formats of files.  The exact
+layout of the different formats depends on the target environment.
+
+The target "default" means the first one known (usually used for
+environments that only support one format, or where the common format
+is known at compile or link time).  The target NULL means the one
+specified at runtime in the environment variable GNUTARGET; if that is
+null or not defined then the first entry in the target list is chosen
+(on output), or all targets are searched (on input) to find a matching
+one..
+
+Most programs should use the target NULL.
+
+There is a way to get a list of the names of all the targets:
+char**   bfd_target_list ()
+         This function returns a freshly-malloced list of all the
+         defined targets (or NULL if it could not malloc).  The names
+         are read-only.  You could use this to prompt the user, or
+         perhaps to error-check.
+
+char * bfd_format_string (bfd_format format)
+     This function will give you a printable, single-word description
+     (like "core" or "archive") for a bfd format.
+\f
+Error handling
+
+General rules:
+funtions which are boolean return true on success and false on failure
+(unless they're a predicate).  Functions which return pointers to
+objects return NULL on error.  The specifics are documented with each
+function.
+
+If a function fails, you should check the variable bfd_error.  If the
+value is no_error, then check the C variable errno just as you would
+with any other program.  The other values bfd_error may take on are
+documented in bfd.h.
+
+If you would prefer a comprehensible string for the error message, use
+the function bfd_errmsg:
+       char * bfd_errmsg (error_tag)
+This function returns a read-only string which documents the error
+code.  If the error code is no_error then it will return a string
+depending on the value of errno.
+
+bfd_perror() is like the perror() function except it understands
+bfd_error.
+\f
+Operations on bfds themselves
+
+bfd *  bfd_openr  (char *filename, char *target);
+bfd *  bfd_fdopenr  (int fd, char *target, char *filename);
+
+       Open a binary file for reading.  TARGET is the type of the file,
+       a char string like "sun4os4" or "elf".  (Note this is not the
+       "function" of the file, e.g. an object versus a core file
+       versus an archive, but instead describes how all these files
+       are encoded.)  Returns a new bfd or NULL upon failure.
+       
+bfd *  bfd_openw  (char *filename, char *target);
+
+       Open a file named `filename'  for writing.  If an existing
+       file has the same name, then it will be overwritten by a
+       successful bfd_close on the returned bfd.  Will return either
+       a new bfd or NULL upon failure.
+
+boolean  bfd_close  (bfd *abfd);
+       
+       Close a BFD opened for either reading or writing.  May involve
+       several filesystem operations, depending on the data format;
+       some things may not be known to the system until file-closing
+       time.  Returns true if it successfully wrote the file, false
+       if not.  A false return will not leave a partially-written
+       file behind with the name supplied to bfd_openw.
+
+       On a bfd open for reading will generally successfully
+       complete.
+
+       It is an error to call this on a file opened from inside an
+       archive.
+
+       FIXME -- show which error codes may be recoverable and
+       followed by another call to bfd_close!
+
+
+The defined formats are specified by the enumeration bfd_format.
+       
+boolean  bfd_check_format  (bfd *abfd, bfd_format format);
+
+       This routine must be called after a bfd_openr.  It sets up
+       internal data structures based on the contents of the file.
+       It returns FALSE if the file is not really in the specified
+       format.
+
+boolean  bfd_set_format  (bfd *abfd, bfd_format format);
+
+       This routine must be called after a bfd_openw.  It sets up
+       internal data structures for the proper format of file.
+       It returns FALSE if that format is not supported for output
+       (e.g. core files).
+
+The following macros may be used to obtain information about a bfd:
+
+bfd_get_filename -- returns a pointer to a null-terminated string
+       which names the bfd's file, or NULL if that is not known.
+       Don't side-effect this string!
+bfd_get_format -- returns the format code for the bfd.
+bfd_get_target -- returns the string which names the bfd's target.
+bfd_get_mtime -- returns an time_t indicating the modification time of an
+             input bfd, if that could be determined, or 0 of not.
+\f
+Object files have certain properties.  For input bfds, these
+properties may be read at any time.  For output bfds you should set
+them before you begin building any sections.
+       
+bfd_vma        bfd_get_start_address  (bfd *abfd);
+
+       Returns the address in an object file where execution will begin.
+
+boolean        bfd_set_start_address   (bfd *abfd, int vma);  
+
+       Set the address where execution will start in an object file.
+
+       If the address you select is incorrect for your architecture
+       (for instance, if it's required to be on a page_boundary and
+       your supplied starting address is not, then you may get the
+       invalid_operation error.  It is not always possible to
+       generate an error in this case.
+
+An object file has an architecture, which is the general instruction
+set of the instructions that it contains.  Architectures are defined in
+enum bfd_architecture in bfd.h.  New architectures can be added by
+putting them in the enum, updating architectures.c, and adding code to
+handle them for the object files that know that architecture.  The
+bfd_architecture values are not stored in files, but are only used
+within the BFD library and its callers.
+
+An object file also has a machine type, which is the specific machine
+within the architecture.  For example, if the architecture is bfd_arch_m68k,
+the Motorola 68000 series, then the machine type might be 68010, the mc68010
+chip.  For architectures such as the SPARC where specific versions of
+the architecture exist, the version number should probably be used.
+
+Particular object file formats may or may not store the machine architecture
+and type.  When copying an object file, you should copy these fields.
+Most callers of BFD will not need to know the particular values that
+these fields contain, but will instead propagate them from file to file,
+or compare the architectures from two files.
+
+enum bfd_architecture bfd_get_architecture (bfd *abfd);
+unsigned long bfd_get_machine     (bfd *abfd);
+
+       Get the machine type and architecture.
+
+boolean bfd_set_arch_mach         (bfd *abfd, enum bfd_architecture arch,
+                                   unsigned long machine);
+
+       Set the architecture and machine type.  The result is true
+       if the object file can exactly represent the specified type.
+       The result is false otherwise.
+
+boolean bfd_arch_compatible       (bfd *abfd, bfd *bbfd,
+                                   enum bfd_architecture *res_arch,
+                                   unsigned long *res_machine);
+
+       Decides whether two BFD's contain compatible architectures and
+       machine types.  If the result is TRUE and the res_arch and
+       res_machine pointers are non-NULL, the resulting "merged" 
+       architecture and machine type are returned through the pointers.
+       A linker could call this to decide whether two object files
+       can be linked, and to deterine the arch and machine type of
+       the resulting file.
+
+char * bfd_printable_arch_mach     (enum bfd_architecture arch,
+                                   unsigned long machine);
+
+       Returns a printable string that represents the particular
+       combination of architecture and machine type.
+
+boolean bfd_scan_arch_mach        (char *string, enum bfd_architecture *archp,
+                                   unsigned long *machinep);
+
+       Examines a printable string and tries to extract an
+       architecture and machine type from it.  The intended use is for
+       parsing specifications from the user, e.g. command line
+       arguments.  The result is true if a known architecture was
+       found, and the resulting architecture and machine type are
+       stored through the argument pointers.  Note that an
+       architecture scannable by this function might not be
+       representable by the particular object file format in use.
+       (i.e. bfd_set_arch_mach might return false).
+
+
+There are also a number of boolean flags which apply to object bfds.
+
+flagword bfd_get_file_flags       (bfd *abfd); 
+
+        returns a flagword containing the bfd's flags.
+
+boolean bfd_set_file_flags        (bfd *abfd, flagword flags,
+                                       boolean on_or_off); 
+
+       sets (on_or_off == true) or clears (on_or_off == false) the flags
+       specified by flagword.  All other flags are unaffected.
+       Some flag combinations don't make sense; It is not always
+       possible to detect them (since they may depend on other information).
+       Returns true if the flags could be modified as requested,
+       false if not.  Upon a false return, no flags will have been
+       altered.
+
+
+flagword bfd_applicable_file_flags     (bfd *abfd); 
+
+        returns a flagword with bits set for all the flags which are
+        meaningful for the bfd.
+
+The flags are:
+    HAS_RELOC -- file contains unresolved relocation information.
+    EXEC_P -- file can be executed.  These two may both be on in the
+             case of some dynamically-linked binaries.
+    HAS_LINENO -- has line number information.
+    HAS_DEBUG -- has debugging information.
+    HAS_SYMS -- has any symbols.
+    HAS_LOCALS -- has local symbols.
+    DYNAMIC -- binary is dynamically linked.
+    WP_TEXT -- text is write-protected
+    D_PAGED -- binary should be demand-paged
+
+These flags are one bit wide and may be OR-ed together with |.
+
+If you are building a large application with bfd there may be data
+specific to your program that you may wish to associate with a bfd.
+Rather than require you to build a parallel table structure, bfd
+provides a void* pointer in each bfd for arbitrary user data.  The
+macro bfd_usrdata (bfd *abfd) extracts these data; you may set them
+with = (ie bfd_usrdata (my_bfd) = frob_it (my_bfd, moon_phase);).
+\f
+Object and core files have sections.
+
+File sections are represented by opaque pointers.  You may map over
+the sections of a file or you may ask for one by name.  Note that not
+all files may have all the possible sections.
+
+Section pointers are valid from the time you get them until the bfd
+to which they refer is closed.
+
+When doing output, you must set up all the file's sections before
+outputting to any.   All that means is that all the file's sections
+must have already been created and their size set before output
+commences.
+
+Each section contains some small information, plus three chunks of
+data in the object file:  contents, relocation, and line numbers.
+In some file formats (e.g. a.out), the line number part is always
+empty, and line number information (if any) is instead recorded in
+the symbol table.
+
+sec_ptr        bfd_get_section_by_name (bfd *abfd, char *name); 
+       Returns a section named NAME, or NULL if none by that name
+       exists.  Works on input and output bfds.
+
+sec_ptr        bfd_make_section        (bfd *abfd, char *name); 
+       Creates a section named name in the output bfd abfd.
+       returns NULL if it cannot create the section (if, for instance,
+       the output format does not permit such a section).  If a
+       section with that name already exists, it is returned; a new
+       one with the same name is NOT created.
+
+unsigned int bfd_count_sections (bfd *abfd)
+
+       This function returns the number of sections in the bfd abfd.
+
+void   bfd_map_over_sections   (bfd *abfd, void (*operation)(),
+                                void *user_storage); 
+
+       This is how you operate on all sections of an input file.
+       Pass in a function pointer.  The function will be called for each
+       section of the file, in random order.  It will be passed
+       three arguments: the bfd, the sec_ptr for the section, and
+       whatever was passed in as user_storage.
+
+char * bfd_section_name        (bfd *abfd, sec_ptr ptr); 
+
+       Produces the name of a section, e.g. ".text" or ".data".
+       This will produce arbitrary names for files with extensible
+       section names (e.g. COFF, ELF) so don't assume that you will
+       only see a few values here.
+
+long   bfd_section_size        (bfd *abfd, sec_ptr ptr); 
+
+       The size of a section in bytes.  Result == -1 for error.
+
+boolean        bfd_set_section_size    (bfd *abfd, sec_ptr section unsigned long size);
+
+       Set the size of a section.  This must be done before any data
+       transfer is done for the section.
+
+bfd_vma        bfd_section_vma (bfd *abfd, sec_ptr ptr); 
+
+       Virtual memory address where a section "belongs".
+
+boolean        bfd_set_section_vma     (bfd *abfd, bfd_vma vma);
+
+       Set the virtual memory address of a section.
+
+int bfd_get_section_alignment  (bfd *abfd, sec_ptr ptr); 
+
+        returns the alignment of a section.  If alignment is not
+       possible, return value is undefined.
+       
+boolean bfd_set_section_alignment  (bfd *abfd, sec_ptr ptr, int alignment) 
+
+       returns true if it can set the section to the requested value.
+       Alignment is an integer; it refers to the power of two
+       specifying the byte boundary we want (ie 0 is byte-aligned; 4
+       is word aligned).  If the requested alignment is not available
+       any existing value is unchanged.
+
+Sections have properties just as object files may:
+
+flagword bfd_get_section_flags    (bfd *abfd, sec_ptr section); 
+
+        returns a flagword containing the section's flags.
+
+boolean bfd_set_section_flags     (bfd *abfd, sec_ptr section,
+                                       flagword flags, boolean on_or_off); 
+
+       sets (on_or_off == true) or clears (on_or_off == false) the flags
+       specified by flagword.  All other flags are unaffected.
+       Some flag combinations don't make sense; It is not always
+       possible to detect them (since they may depend on other information).
+       Returns true if the flags could me modified as requested,
+       false if not.  Unpon a false return, no flags will have been
+       altered.
+
+flagword bfd_applicable_section_flags  (bfd *abfd); 
+
+        returns a flagword with bits set for all the flags which are
+        meaningful for a section.
+
+The flags are:
+
+    SEC_BALIGN -- segment can be byte-aligned.
+    SEC_RELOC -- segment should be relocated.
+    SEC_ALLOC -- when converted into a memory image with the intent of
+           constructing a runable process, memory space will be
+           allocated for this section.
+    SEC_LOAD -- when converted into a memory image with the intent of
+           constructing a runable process, section contents will be
+           copied from the object file into memory.  When this flag
+           is set, SEC_ALLOC is guaranteed to also be set.
+    SEC_HAS_CONTENTS -- The contents of this section exist in the
+           object file.  Sections whose contents do not exist in the
+           object file may still have their contents read.  On read,
+           a segment filled with zeroes will be invented to satisfy
+           the read request.  It is an error to attempt to set the
+           contents of a section that has no contents.
+
+These last three probably need some explanation.  In a traditional,
+native unix object format, there are three real sections, text, data,
+and bss.  The text section will be allocated memory on exec, and will
+be loaded from file into memory on exec.  So the flags for a
+traditional unix text section would typically be at least (SEC_ALLOC |
+SEC_LOAD | SEC_HAS_CONTENTS).  The data section has basically these
+same traits.  The bss section, however is a little different.  It is
+not relocated, and it is not loaded from file on exec, but it is
+allocated memory on exec.  Thus, its flags would be more like
+(SEC_ALLOC).  It is possible to have a section which is the converse
+of the bss section.  That is, (SEC_HAS_CONTENTS & ~SEC_ALLOC).  This
+could be anything from profiling information or notes from one pass of
+a toolchain to another to time and version stamp information.
+
+Note that the section flags currently lack information on position
+dependance.
+
+boolean        bfd_get_section_contents  (bfd *abfd, sec_ptr section,
+                                  unsigned char *location,
+                                  int offset, int count); 
+
+       Stores count bytes from the section's contents starting at
+       offset from within those contents.  The values are stored into
+       location.  Returns true if it could do so.  Supplying invalid
+       values for offset and count will produce unpredictable results.
+
+boolean        bfd_set_section_contents (bfd *abfd, sec_ptr section,
+                                unsigned char *location,
+                                int offset, int count); 
+       Stores count bytes from location into offset within the
+       section contents.  You need not write all the contents contiguously
+       (that is, you may write words 5-7 followed by 0-4 if you
+       wish).  However once you start writing into a section, any
+       other sections into which you have previously written are
+       considered finished, and you may not write in them any more.
+
+*** Line numbers ***
+
+bfd_get_section_lineno_size (bfd *abfd, sec_ptr section);
+       Returns how many bytes of line numbers are associated with this
+       section.
+
+bfd_set_section_lineno_size (bfd *abfd, sec_ptr section, unsigned long val);
+       Sets the number of bytes of line numbers that this section should
+       contain.
+
+boolean bfd_get_section_linenos (bfd *abfd, sec_ptr section,
+                                unsigned char *location,
+                                int offset, int count); 
+       Same as get_section_contents, except that it works on the linenos
+       for this section.
+
+boolean bfd_set_section_linenos (bfd *abfd, sec_ptr section,
+                                unsigned char *location,
+                                int offset, int count); 
+       Same as set_section_contents, except that it works on the linenos
+       for this section.
+
+As with files, you may associate arbitrary program-specific data with
+a section of a bfd.  The following two functions are provided for
+manipulating these data:
+
+void * bfd_get_section_userdata (bfd *abfd, sec_ptr section)
+       Returns whatever was stored in section's user data, or NULL if nothing.
+
+boolean bfd_set_section_userdata (bfd *abfd, sec_ptr section, void *contents)
+       Set the section contents.  Returns true if it can, false if not.
+\f
+Core files
+
+Core files are currently only supported for reading.
+
+Apart from opening them, looking at the various sections (generally
+the .data, .stack, and .regs sections; maybe a .user_struct section
+eventually), you can make some queries about the status of the core
+file, detailed below.  The ".regs" section contains the general and
+floating point registers of the process that died, in some machine-
+specific order and format "intended to be unsurprising to someone who
+knows the machine".
+
+char *  bfd_core_file_failing_command  (bfd *abfd);
+
+       The command name of the program that failed, creating the core file.
+       The result is NULL if BFD can't figure out what the failing command was.
+
+int  bfd_core_file_failing_signal  (bfd *abfd);
+
+       The signal number which caused the program to die, causing the
+       core file to be created.  It will be positive if valid.
+
+boolean        core_file_matches_executable_p  (bfd *core_bfd, bfd *exec_bfd);
+
+       For debuggers, checks whether a core file "matches" (is likely to
+       have come from) an executable file.  This will not be perfect on
+       most systems, but will just provide a way to reject gross mismatches.
+\f
+Archives.
+
+An archive is a special file which can contain other files.
+Originally it was intended to be a general way to group files, the way
+tar is today.  But now it is used almost exclusively to hold object
+files.
+
+An archive may be opened for reading or writing just like any other
+bfd.  Once it is open for reading you may obtain bfds for each of the
+files contained within it with the following function:
+
+bfd *  bfd_openr_next_archived_file    (bfd *arch_bfd, bfd *last_file);
+
+       If called with NULL as the second argument, returns the first
+       file contained in the archive arch_bfd.  If called with a file
+       contained within arch_bfd, returns the one which follows that
+       one, or NULL if it was the last.  Returns NULL also if the
+       bfd supplied as last_file did not come from the archive arch_bfd.
+                                                      
+Any bfd open for read may be placed in an output archive.  When the
+output archive is closed, the contents will be placed into the
+archive.
+
+You control the order of files in an archive.  You set the first one
+with the following function:
+
+boolean bfd_set_archive_head (bfd *output_archive, bfd *new_head)
+
+       This function sets the first file in the archive
+       output_archive to be the bfd new_head.
+
+bfd's contain a pointer called next, which is bfd *.  It is used by
+bfd_close when an archive is closed to decide which file should next
+go into the archive.  So to place a group of files into an archive,
+open bfds for each of them, chain them together using the next pointer
+in the order you desire (be sure to store NULL into the final one's
+next pointer), then do bfd_set_archive_head with the head of the
+chain.  The next pointer may be freely smashed at any time; it is only
+looked at when closing an output archive.
+
+bfds for files contained within archives are normal bfds; you can do
+any input operations on them that you can do with a normal bfd.
+
+bfd_my_archive is a macro which takes an input bfd and returns NULL if
+it lives in the filesystem and a bfd if it is contained in an archive.
+In the latter case, the returned bfd is the archive itself.
+
+Archives containing only object files may have a "map" -- a table in
+the front which maps external symbols to the files which contain them.
+
+Archive maps will refer only to object files; if an archive contains a
+file which is not an archive that file will of course not appear in
+the map.        
+        
+boolean  bfd_has_map (bfd *archive_bfd)
+
+        This macro takes a bfd of an archive and returns true or
+        false depending on whether the bfd has a map.  For output
+        bfds this may be set to true or false, depending on whether
+        you want the map to be maintained or not.  For some targets,
+        setting this to false will cause no map to be generated; for
+        others it will merely cause an empty map to be created, since
+        a map is required by that target.
+
+For archives with maps you may use the following function:
+
+int bfd_get_next_mapent (bfd *abfd, int prev, char **name)
+
+    You may use this to step through all the entries in the archive
+    map.  Supply BFD_NO_MORE_SYMBOLS as the 'prev' entry to get the
+    first entry; then use successive returned values from this
+    function to get the succeeding ones.  The name of the next entry
+    will be stored through the pointer name.
+
+    This function returns BFD_NO_MORE_SYMBOLS when there are no more
+    entries or on error.
+bfd * bfd_get_elt_at_index (abfd, int index)
+
+    This function takes an index as returned by bfd_get_next_mapent
+    and returns the bfd which corresponds to that entry.  Returns NULL
+    on error.
+\f
+Symbol and relocation information.
+
+Symbol-table information is the area of greatest incompatibility.
+bfd has a canonical symbol representation; all formats are parsed into
+and out of it.
+
+Note that canonicalize_symtab takes a pointer to an array of pointers
+to canonical symbols.  This is necessary so that the end of the array
+can be marked with NULL.  You may shuffle the pointers and you may
+clobber the symbol contents.  But don't move the symbols themselves.
+
+unsigned int bfd_get_symtab_upper_bound        (bfd *abfd);
+
+       Returns the maximum number of bytes that would be taken by
+       the output of canonicalize_symtab.  Returns 0 on error.
+                                                             
+unsigned int bfd_canonicalize_symtab (bfd *abfd, asymbol **location);
+
+       Produces a symbol table in canonical format at LOCATION, which 
+       must be of size specified by get_symtab_upper_bound bytes.
+       Not all those bytes may be used.   Returns the number of
+       symbol pointers written.  Returns 0 upon error.
+
+boolean        bfd_set_symtab  (bfd *outbfd, asymbol **location,
+                       unsigned int symcount);
+
+       Takes a generic symbol table and an output bfd.  Used to set
+       the symbol table for an output bfd.  Do not change the table
+       after using this function (although the storage may be
+       reclaimed once the bfd has been closed).
+       
+If you're done with the symol table you can tell bfd about it by
+calling bfd_reclaim_symbol_table, which takes a bfd.  Calling this
+function will also reclaim any relocation entries you may have
+requested.  If you don't use this function bfd will keep around all
+symbol information until the bfd is closed.
+
+Similarly, relocations have a canonical format.  See the file bfd.h for
+the exact definition.  It is similar to the sun-4 relocation format.
+Please note that:
+o - Each relocation has a pointer to a generic symbol.
+o - Not all values of reloc_type are supported for all targets.  There
+    is a bitvector which explains which are; you can index into it by
+    relocation type.  The macro which extracts it is bfd_valid_reloc_types.
+
+Since relocation information is saved on a per-section basis, the
+interface is slightly different from that of the symbol table:
+
+unsigned int get_reloc_upper_bound     (bfd *abfd, sec_ptr asect);
+
+       Returns the maximum number of bytes that would be taken by
+       the output of canonicalize_reloc.  Returns 0 on error.
+
+unsigned int canonicalize_reloc (bfd *abfd, sec_ptr asect, arelent *location);
+
+       Produces a relocation table in canonical format at LOCATION,
+       which must be of size specified by get_reloc_upper_bound
+       bytes.  Not all those bytes may be used.  Returns the number
+       of entries written.  Returns 0 upon error.
+
+boolean        bfd_set_reloc   (bfd *outbfd, sec_ptr asect, arelent *location,
+                        unsigned int count);
+
+       Takes a generic reloc table and an output bfd.  Used to set
+       the reloc table for an output bfd.  Do not change the table
+       after using this function (although the storage may be
+       reclaimed once the bfd has been closed).
+\f
+Byte-swapping
+
+Unfortunately, not all machines have the same byte order.  Worse,
+storage layout is in general highly machine-dependent.  Although bfd
+can hide that from you in most cases, it cannot do so with the section
+contents, since they are totally uninterpreted.  Hence you must
+byte-swap those data yourself.  This is not usually much of an issue
+since you should just generate your data in the correct byte order.
+
+[THIS IS WRONG AND ALSO DOES NOT REFLECT THE CODE WHICH IS CORRECT]
+
+Fortunately, bfd can tell if byte-swapping or realignment is required
+at all!  The macro bfd_bit_twiddle_required takes a pointer to a bfd
+and returns true if byte-swapping is required, false if not.
+
+However if you don't wish to check this you may just use the following
+functions which will do the conversions required:
+
+
+long   bfd_getlong     (bfd *abfd, unsigned char *ptr);
+       bfd_putlong     (bfd *abfd, unsigned char *ptr, long time);
+
+short  bfd_getshort    (bfd *abfd, unsigned char *ptr);
+       bfd_putshort    (bfd *abfd, unsigned char *ptr, short stop);
+
+       These functions take a pointer that points to data which is,
+       or will be, part of a section contents.  They extract numbers
+       from the data, or insert numbers into the data.  The argument
+       or result is in the host's number format; the data stored at
+       the pointer or retrieved from it is in the target's number format.
+       Typically this transfer is either a no-op or is a byte-swap;
+       sometimes it involves an access to a "misaligned" location from
+       the host's point of view..
diff --git a/bfd/cplus-dem.c b/bfd/cplus-dem.c
new file mode 100755 (executable)
index 0000000..edb9e39
--- /dev/null
@@ -0,0 +1,942 @@
+/* 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. */
+
+/* #define nounderscore 1 /* define this is names don't start with _ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+/* #include "misc.h" */
+
+#ifdef USG
+#include <memory.h>
+#else
+#define memcpy(s1, s2, n) strncpy(s1, s2, n) 
+#define memcmp(s1, s2, n) strncmp(s1, s2, n)
+#define strchr(s, c) index(s, c) 
+#endif
+
+#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 *) zalloc (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 **) realloc ((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] == '$')
+    {
+      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 *) realloc (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/bfd/filemode.c b/bfd/filemode.c
new file mode 100644 (file)
index 0000000..1bb5e64
--- /dev/null
@@ -0,0 +1,193 @@
+/* filemode.c -- make a string describing file modes
+   Copyright (C) 1985, 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.  */
+\f
+#include <sys/types.h>
+#include <sys/stat.h>
+
+void mode_string ();
+static char ftypelet ();
+static void rwx ();
+static void setst ();
+
+/* filemodestring - fill in string STR with an ls-style ASCII
+   representation of the st_mode field of file stats block STATP.
+   10 characters are stored in STR; no terminating null is added.
+   The characters stored in STR are:
+
+   0   File type.  'd' for directory, 'c' for character
+       special, 'b' for block special, 'm' for multiplex,
+       'l' for symbolic link, 's' for socket, 'p' for fifo,
+       '-' for any other file type
+
+   1   'r' if the owner may read, '-' otherwise.
+
+   2   'w' if the owner may write, '-' otherwise.
+
+   3   'x' if the owner may execute, 's' if the file is
+       set-user-id, '-' otherwise.
+       'S' if the file is set-user-id, but the execute
+       bit isn't set.
+
+   4   'r' if group members may read, '-' otherwise.
+
+   5   'w' if group members may write, '-' otherwise.
+
+   6   'x' if group members may execute, 's' if the file is
+       set-group-id, '-' otherwise.
+       'S' if it is set-group-id but not executable.
+
+   7   'r' if any user may read, '-' otherwise.
+
+   8   'w' if any user may write, '-' otherwise.
+
+   9   'x' if any user may execute, 't' if the file is "sticky"
+       (will be retained in swap space after execution), '-'
+       otherwise.
+       'T' if the file is sticky but not executable. */
+
+void
+filemodestring (statp, str)
+     struct stat *statp;
+     char *str;
+{
+  mode_string (statp->st_mode, str);
+}
+
+/* Like filemodestring, but only the relevant part of the `struct stat'
+   is given as an argument. */
+
+void
+mode_string (mode, str)
+     unsigned short mode;
+     char *str;
+{
+  str[0] = ftypelet (mode);
+  rwx ((mode & 0700) << 0, &str[1]);
+  rwx ((mode & 0070) << 3, &str[4]);
+  rwx ((mode & 0007) << 6, &str[7]);
+  setst (mode, str);
+}
+
+/* Return a character indicating the type of file described by
+   file mode BITS:
+   'd' for directories
+   'b' for block special files
+   'c' for character special files
+   'm' for multiplexor files
+   'l' for symbolic links
+   's' for sockets
+   'p' for fifos
+   '-' for any other file type. */
+
+static char
+ftypelet (bits)
+     unsigned short bits;
+{
+  switch (bits & S_IFMT)
+    {
+    default:
+      return '-';
+    case S_IFDIR:
+      return 'd';
+#ifdef S_IFLNK
+    case S_IFLNK:
+      return 'l';
+#endif
+#ifdef S_IFCHR
+    case S_IFCHR:
+      return 'c';
+#endif
+#ifdef S_IFBLK
+    case S_IFBLK:
+      return 'b';
+#endif
+#ifdef S_IFMPC
+    case S_IFMPC:
+    case S_IFMPB:
+      return 'm';
+#endif
+#ifdef S_IFSOCK
+    case S_IFSOCK:
+      return 's';
+#endif
+#ifdef S_IFIFO
+#if S_IFIFO != S_IFSOCK
+    case S_IFIFO:
+      return 'p';
+#endif
+#endif
+#ifdef S_IFNWK                 /* HP-UX */
+    case S_IFNWK:
+      return 'n';
+#endif
+    }
+}
+
+/* Look at read, write, and execute bits in BITS and set
+   flags in CHARS accordingly. */
+
+static void
+rwx (bits, chars)
+     unsigned short bits;
+     char *chars;
+{
+  chars[0] = (bits & S_IREAD) ? 'r' : '-';
+  chars[1] = (bits & S_IWRITE) ? 'w' : '-';
+  chars[2] = (bits & S_IEXEC) ? 'x' : '-';
+}
+
+/* Set the 's' and 't' flags in file attributes string CHARS,
+   according to the file mode BITS. */
+
+static void
+setst (bits, chars)
+     unsigned short bits;
+     char *chars;
+{
+#ifdef S_ISUID
+  if (bits & S_ISUID)
+    {
+      if (chars[3] != 'x')
+       /* Set-uid, but not executable by owner. */
+       chars[3] = 'S';
+      else
+       chars[3] = 's';
+    }
+#endif
+#ifdef S_ISGID
+  if (bits & S_ISGID)
+    {
+      if (chars[6] != 'x')
+       /* Set-gid, but not executable by group. */
+       chars[6] = 'S';
+      else
+       chars[6] = 's';
+    }
+#endif
+#ifdef S_ISVTX
+  if (bits & S_ISVTX)
+    {
+      if (chars[9] != 'x')
+       /* Sticky, but not executable by others. */
+       chars[9] = 'T';
+      else
+       chars[9] = 't';
+    }
+#endif
+}
+
+