diff options
-rw-r--r-- | bfd/VERSION | 1 | ||||
-rwxr-xr-x | bfd/aout.c | 5 | ||||
-rwxr-xr-x | bfd/bfd.doc | 705 | ||||
-rwxr-xr-x | bfd/cplus-dem.c | 942 | ||||
-rw-r--r-- | bfd/filemode.c | 193 |
5 files changed, 1845 insertions, 1 deletions
diff --git a/bfd/VERSION b/bfd/VERSION new file mode 100644 index 0000000..ba66466 --- /dev/null +++ b/bfd/VERSION @@ -0,0 +1 @@ +0.0 @@ -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 index 0000000..3e3183e --- /dev/null +++ b/bfd/bfd.doc @@ -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); ] + } + + + +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. + +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. + +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. + +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. + +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);). + +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. + +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. + +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. + +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). + +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 index 0000000..edb9e39 --- /dev/null +++ b/bfd/cplus-dem.c @@ -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 index 0000000..1bb5e64 --- /dev/null +++ b/bfd/filemode.c @@ -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. */ + +#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 +} + + |