diff options
Diffstat (limited to 'binutils-1.9/nm.c')
| -rw-r--r-- | binutils-1.9/nm.c | 1204 |
1 files changed, 1204 insertions, 0 deletions
diff --git a/binutils-1.9/nm.c b/binutils-1.9/nm.c new file mode 100644 index 0000000..6ba3b66 --- /dev/null +++ b/binutils-1.9/nm.c @@ -0,0 +1,1204 @@ +/* Describe symbol table of a rel file. + Copyright (C) 1986, 1988, 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 <stdio.h> +#include <ar.h> +#include <sys/types.h> +#include <sys/file.h> +#include "getopt.h" + +#if !defined(A_OUT) && !defined(MACH_O) +#define A_OUT +#endif + +#ifdef A_OUT +#ifdef COFF_ENCAPSULATE +#include "a.out.encap.h" +#else +/* On native BSD systems, use the system's own a.out.h. */ +#include <a.out.h> +#endif +#endif + +#ifdef MACH_O +#ifndef A_OUT +#include <nlist.h> +#ifndef N_TEXT +#define N_TEXT 4 +#define N_DATA 6 +#define N_BSS 8 +#endif +#ifndef N_FN +#define N_FN 15 +#endif +#endif +#include <sys/loader.h> +#endif + +/* Always use the GNU version of debugging symbol type codes, if possible. */ +#include "stab.h" + +/* Struct or union for header of object file. */ + +#ifdef USG +#include <string.h> +/* You might need to compile with -I/usr/include/sys if your fcntl.h + isn't in /usr/include (which is where it should be according to POSIX). */ +#include <fcntl.h> +#else +#include <strings.h> +#endif + +/* Alloca definitions and includes... */ + +/* If compiled with GNU C, use the built-in alloca */ +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else +/* If on a sun 4, make sure to include the right definition. */ +#if defined(sun) && defined(sparc) +#include "alloca.h" +#else +char *alloca (); +#endif +#endif + +char *malloc (), *realloc (); + +char *xmalloc (), *xrealloc (); + +/* C++ demangler stuff. */ +char *cplus_demangle (); + +/* Print NAME on STREAM, demangling if necessary. */ +void +fprint_name (stream, name) + FILE *stream; + char *name; +{ + char *demangled = cplus_demangle (name); + if (demangled == NULL) + fputs (name, stream); + else + { + fputs (demangled, stream); + free (demangled); + } +} + +/* Special global symbol types understood by GNU LD. */ + +/* The following type indicates the definition of a symbol as being + an indirect reference to another symbol. The other symbol + appears as an undefined reference, immediately following this symbol. + + Indirection is asymmetrical. The other symbol's value will be used + to satisfy requests for the indirect symbol, but not vice versa. + If the other symbol does not have a definition, libraries will + be searched to find a definition. */ +#ifndef N_INDR +#define N_INDR 0xa +#endif + +/* Warning message symbol. The name of this symbol will be printed if + any symbols from its file are required by the linker. */ +#ifndef N_WARNING +#define N_WARNING 0x1e +#endif + + +/* The following symbols refer to set elements. + All the N_SET[ATDB] symbols with the same name form one set. + Space is allocated for the set in the text section, and each set + element's value is stored into one word of the space. + The first word of the space is the length of the set (number of elements). + + The address of the set is made into an N_SETV symbol + whose name is the same as the name of the set. + This symbol acts like a N_DATA global symbol + in that it can satisfy undefined external references. */ + +#ifndef N_SETA +#define N_SETA 0x14 /* Absolute set element symbol */ +#endif /* This is input to LD, in a .o file. */ + +#ifndef N_SETT +#define N_SETT 0x16 /* Text set element symbol */ +#endif /* This is input to LD, in a .o file. */ + +#ifndef N_SETD +#define N_SETD 0x18 /* Data set element symbol */ +#endif /* This is input to LD, in a .o file. */ + +#ifndef N_SETB +#define N_SETB 0x1A /* Bss set element symbol */ +#endif /* This is input to LD, in a .o file. */ + +/* Macros dealing with the set element symbols defined in a.out.h */ +#define SET_ELEMENT_P(x) ((x)>=N_SETA&&(x)<=(N_SETB|N_EXT)) +#define TYPE_OF_SET_ELEMENT(x) ((x)-N_SETA+N_ABS) + +#ifndef N_SETV +#define N_SETV 0x1C /* Pointer to set vector in text area. */ +#endif /* This is output from LD. */ + +#ifndef __GNU_STAB__ + +/* Line number for the data section. This is to be used to describe + the source location of a variable declaration. */ +#ifndef N_DSLINE +#define N_DSLINE (N_SLINE+N_DATA-N_TEXT) +#endif + +/* Line number for the bss section. This is to be used to describe + the source location of a variable declaration. */ +#ifndef N_BSLINE +#define N_BSLINE (N_SLINE+N_BSS-N_TEXT) +#endif + +#endif /* not __GNU_STAB__ */ + +/* Name of this program. */ + +char *program_name; + +/* Number of input files specified. */ + +int number_of_files; + +/* Current file's name. */ + +char *input_name; + +/* Current member's name, or 0 if processing a non-library file. */ + +char *input_member; + +#ifdef MACH_O +/* Section ordinals for N_SECT references. */ +int text_section; +int data_section; +int bss_section; +#endif + +/* Offset within archive of the current member, + if we are processing an archive. */ + +int member_offset; + +/* Command options. */ + +int external_only; /* nonzero means print external symbols only. */ +int sort_numerically; /* sort in numerical order rather than alphabetic */ +int reverse_sort; /* sort in downward (alphabetic or numeric) order. */ +int no_sort; /* don't sort; print symbols in order in the file. */ +int undefined_only; /* print undefined symbols only. */ +int file_on_each_line; /* print file name on each line. */ +int debugger_syms; /* print the debugger-only symbols. */ +int print_symdefs; /* describe the __.SYMDEF data in any archive file specified. */ + +/* The __.SYMDEF member of an archive has the following format: + 1) A longword saying the size of the symdef data that follows + 2) Zero or more struct symdef filling that many bytes + 3) A longword saying how many bytes of strings follow + 4) That many bytes of string data. +*/ + +struct symdef + { + long stringoffset; /* Offset of this symbol's name in the string data */ + long offset; /* Offset in the archive of the header-data for the member that + defines this symbol. */ + }; + +/* Create a table of debugging stab-codes and corresponding names. */ +#ifdef __GNU_STAB__ +#define __define_stab(NAME, CODE, STRING) {NAME, STRING}, +struct {enum __stab_debug_code code; char *string;} stab_names[] + = { +#include "stab.def" + }; +#undef __define_stab +#endif + +char *concat (); +int decode_arg (); +void decode_switch (); +void do_one_file (); +void do_one_rel_file (); +void do_symdef_member (); +void error (); +void error_with_file (); +void fatal (); +void perror_name (); +void print_file_name (); + +void +main (argc, argv) + char **argv; + int argc; +{ + int i; + int c; + int ind; + static struct option long_options[] = + { + {"all", 0, &debugger_syms, 1}, + {"extern-only", 0, &external_only, 1}, + {"numeric-sort", 0, &sort_numerically, 1}, + {"print-file-name", 0, &file_on_each_line,1}, + {"no-sort", 0, &no_sort, 1}, + {"reverse", 0, &reverse_sort, 1}, + {"print-symdefs", 0, &print_symdefs, 1}, + {"undefined-only",0, &undefined_only, 1}, + {NULL, 0, NULL, 0} + }; + + program_name = argv[0]; + + number_of_files = 0; + external_only = 0; + sort_numerically = 0; + reverse_sort = 0; + no_sort = 0; + undefined_only = 0; + file_on_each_line = 0; + debugger_syms = 0; + print_symdefs = 0; + + while ((c = getopt_long (argc, argv, "agnoprsu", long_options, &ind)) != EOF) + switch (c) + { + case 0: + break; + + case 'a': + debugger_syms = 1; + break; + + case 'g': + external_only = 1; + break; + + case 'n': + sort_numerically = 1; + break; + + case 'o': + file_on_each_line = 1; + break; + + case 'p': + no_sort = 1; + break; + + case 'r': + reverse_sort = 1; + break; + + case 's': + print_symdefs = 1; + break; + + case 'u': + undefined_only = 1; + break; + + default: + fprintf (stderr, "\ +Usage: %s [-agnoprsu] [+all] [+extern-only] [+numeric-sort]\n\ + [+print-file-name] [+no-sort] [+reverse] [+print-symdefs]\n\ + [+undefined-only] [file...]\n", program_name); + exit (1); + break; + } + + number_of_files = argc - optind; + + /* Now scan again and print the files. */ + + if (argc == optind) + do_one_file ("a.out"); + else + for (i = optind; i < argc; i++) + do_one_file (argv[i]); + + exit (0); +} + +/* Print the filename of the current file on 'outfile' (a stdio stream). */ + +void +print_file_name (outfile) + FILE *outfile; +{ + fprintf (outfile, "%s", input_name); + if (input_member) + fprintf (outfile, "(%s)", input_member); +} + +/* process one input file */ +void scan_library (); + +void +do_one_file (name) + char *name; +{ + int desc, nchars; + char armag[SARMAG]; + + desc = open (name, O_RDONLY, 0); + + if (desc < 0) + { + perror_name (name); + return; + } + + input_name = name; + input_member = 0; + + nchars = read (desc, armag, SARMAG); + if (nchars == SARMAG && !strncmp(armag, ARMAG, SARMAG)) + scan_library (desc); + else + do_one_rel_file (desc, 0); + + close (desc); +} + +/* Read in the archive data about one member. + SUBFILE_OFFSET is the address within the archive of the start of that data. + + Return the length of the member's contents, which does + not include the archive data about the member. + A pointer to the member's name is stored into *MEMBER_NAME_PTR. + If there are no more valid members, return zero. */ + +int +decode_library_subfile (desc, subfile_offset, member_name_ptr) + int desc; + int subfile_offset; + char **member_name_ptr; +{ + int bytes_read; + int namelen; + int member_length; + char *name; + struct ar_hdr hdr1; + + lseek (desc, subfile_offset, 0); + + bytes_read = read (desc, &hdr1, sizeof hdr1); + if (!bytes_read) + ; /* end of archive */ + + else if (sizeof hdr1 != bytes_read) + error_with_file ("malformed library archive "); + + else if (sscanf (hdr1.ar_size, "%d", &member_length) != 1) + error_with_file ("malformatted header of archive member in "); + + else + { + for (namelen = 0; ; namelen++) + if (hdr1.ar_name[namelen] == 0 || hdr1.ar_name[namelen] == ' ' + /* Some systems use a slash? Strange. */ + || hdr1.ar_name[namelen] == '/') + break; + + name = (char *) xmalloc (namelen+1); + strncpy (name, hdr1.ar_name, namelen); + name[namelen] = 0; + + *member_name_ptr = name; + + return member_length; + } + return 0; /* tell caller to exit loop */ +} + +/* Scan a library and describe each member. */ + +void +scan_library (desc) + int desc; +{ + int this_subfile_offset = SARMAG; + int member_length; + + if (!file_on_each_line) + printf ("\n%s:\n", input_name); + + while (1) + { + member_length + = decode_library_subfile (desc, this_subfile_offset, &input_member); + if (member_length == 0) + break; + + /* Describe every member except the ranlib data if any. */ + + if (strcmp (input_member, "__.SYMDEF")) + do_one_rel_file (desc, this_subfile_offset + sizeof (struct ar_hdr)); + else if (print_symdefs) + do_symdef_member (desc, this_subfile_offset + sizeof (struct ar_hdr), member_length); + + this_subfile_offset += ((member_length + sizeof (struct ar_hdr)) + 1) & -2; + } +} + +/* Read a file's header and fill in various pieces of information. + Return 0 on failure. */ + +int +read_header_info (desc, offset, syms_offset, syms_size, strs_offset, strs_size) + int desc; + long int offset; + long int *syms_offset; + unsigned int *syms_size; + long int *strs_offset; + unsigned int *strs_size; +{ + int len; + +#ifdef A_OUT + { + struct exec hdr; + + lseek (desc, offset, 0); +#ifdef HEADER_SEEK_FD + /* Skip the headers that encapsulate our data in some other format + such as COFF. */ + HEADER_SEEK_FD (desc); +#endif + len = read (desc, (char *) &hdr, sizeof (struct exec)); + if (len == sizeof (struct exec) && !N_BADMAG (hdr)) + { + *syms_offset = N_SYMOFF(hdr); + *syms_size = hdr.a_syms; + *strs_offset = N_STROFF(hdr); + lseek(desc, N_STROFF(hdr) + offset, 0); + if (read (desc, (char *) strs_size, sizeof *strs_size) != sizeof *strs_size) + { + error_with_file ("cannot read string table size in "); + return 0; + } + return 1; + } + } +#endif + +#ifdef MACH_O + { + struct mach_header mach_header; + char *hdrbuf; + struct load_command *load_command; + struct segment_command *segment_command; + struct section *section; + struct symtab_command *symtab_command; + int symtab_seen; + int len, cmd, seg, ordinal; + + symtab_seen = 0; + + lseek (desc, offset, 0); + len = read (desc, (char *) &mach_header, sizeof (struct mach_header)); + if (len == sizeof (struct mach_header) && mach_header.magic == MH_MAGIC) + { + hdrbuf = xmalloc (mach_header.sizeofcmds); + len = read (desc, hdrbuf, mach_header.sizeofcmds); + if (len != mach_header.sizeofcmds) + { + error_with_file ("failure reading Mach-O load commands in "); + return 0; + } + load_command = (struct load_command *) hdrbuf; + ordinal = 1; + for (cmd = 0; cmd < mach_header.ncmds; ++cmd) + { + switch (load_command->cmd) + { + case LC_SEGMENT: + segment_command = (struct segment_command *) load_command; + section = (struct section *) ((char *) (segment_command + 1)); + for (seg = 0; seg < segment_command->nsects; ++seg, ++section, ++ordinal) + { + if (!strncmp(SECT_TEXT, section->sectname, sizeof section->sectname)) + text_section = ordinal; + else if (!strncmp(SECT_DATA, section->sectname, sizeof section->sectname)) + data_section = ordinal; + else if (!strncmp(SECT_BSS, section->sectname, sizeof section->sectname)) + bss_section = ordinal; + } + break; + case LC_SYMTAB: + if (symtab_seen) + error_with_file ("more than one LC_SYMTAB in "); + else + { + symtab_seen = 1; + symtab_command = (struct symtab_command *) load_command; + *syms_offset = symtab_command->symoff; + *syms_size = symtab_command->nsyms * sizeof (struct nlist); + *strs_offset = symtab_command->stroff; + *strs_size = symtab_command->strsize; + } + break; + } + load_command = (struct load_command *) + ((char *) load_command + load_command->cmdsize); + } + free (hdrbuf); + return 1; + } + } +#endif + + return 0; +} + +void print_symbols (); +void print_one_symbol (); +void read_header (); +int alphacompare (); +int valuecompare (); +int filter_symbols (); + +void +do_one_rel_file (desc, offset) + int desc; + int offset; +{ + struct nlist *symbols_and_strings; + int symcount; + int totalsize; + char *strings; + long int syms_offset, strs_offset; + unsigned int syms_size, strs_size; + + if (!read_header_info (desc, offset, &syms_offset, &syms_size, &strs_offset, &strs_size)) + { + error_with_file ("malformed input (not a rel file or archive) in "); + return; + } + + /* Number of symbol entries in the file. */ + symcount = syms_size / sizeof (struct nlist); + + totalsize = strs_size + syms_size; + + /* Allocate space for symbol entries and string table. */ + symbols_and_strings = (struct nlist *) xmalloc (totalsize); + strings = (char *) symbols_and_strings + syms_size; + + /* Read them both in. */ + lseek (desc, syms_offset + offset, 0); + if (syms_size != read (desc, (char *) symbols_and_strings, syms_size)) + { + error_with_file ("premature end of file in symbols of "); + return; + } + lseek (desc, strs_offset + offset, 0); + if (strs_size != read (desc, (char *) strings, strs_size)) + { + error_with_file ("premature end of file in strings of "); + return; + } + + /* Identify this file, if desired. */ + + if (!file_on_each_line && (number_of_files > 1 || input_member)) + printf ("\n%s:\n", input_member ? input_member : input_name); + + /* Discard the symbols we don't want to print; compact the rest down. */ + + symcount = filter_symbols (symbols_and_strings, symcount, strings); + + /* Modify each symbol entry to point directly at the symbol name. + This is so the sort routine does not need to be passed + the value of `strings' separately. */ + + { + struct nlist *p = symbols_and_strings; + struct nlist *end = symbols_and_strings + symcount; + + for (; p < end; p++) + { + /* A zero index means there is no string. */ + if (p->n_un.n_strx != 0) + { + if (p->n_un.n_strx > 0 && p->n_un.n_strx < strs_size) + p->n_un.n_name = strings + p->n_un.n_strx; + else + { + error_with_file ("invalid string table offset in "); + return; + } + } + } + } + + /* Sort the symbols if desired. */ + + if (!no_sort) + qsort (symbols_and_strings, symcount, sizeof (struct nlist), + sort_numerically ? valuecompare : alphacompare); + + /* Print the symbols in the order they are now in. */ + + print_symbols (symbols_and_strings, symcount); + + free (symbols_and_strings); +} + +/* Choose which symbol entries to print; + compact them downward to get rid of the rest. + Return the number of symbols to be printed. */ + +int +filter_symbols (syms, symcount, strings) + struct nlist *syms; + int symcount; + char *strings; +{ + struct nlist *from = syms, *to = syms; + struct nlist *end = syms + symcount; + + while (from < end) + { + int keep = 0; + + /* undefined sym or common sym */ + if (from->n_type == N_EXT) keep = !undefined_only || !from->n_value; + /* global defined sym */ + else if (from->n_type & N_EXT) keep = !undefined_only; + /* debugger sym: normally don't print */ + else if (from->n_type & ~(N_TYPE | N_EXT)) keep = debugger_syms; + /* local sym */ + else keep = !external_only && !undefined_only; + + if (keep) + *to++ = *from; + from++; + } + + return to - syms; +} + +/* Comparison functions for sorting symbols. */ + +int +alphacompare (sym1, sym2) + struct nlist *sym1, *sym2; +{ + if (reverse_sort) + { + if (!sym2->n_un.n_name) + { + if (sym1->n_un.n_name) return -1; + else return 0; + } + if (!sym1->n_un.n_name) return 1; + return strcmp (sym2->n_un.n_name, sym1->n_un.n_name); + } + else + { + if (!sym1->n_un.n_name) + { + if (sym2->n_un.n_name) return -1; + else return 0; + } + if (!sym2->n_un.n_name) return 1; + return strcmp (sym1->n_un.n_name, sym2->n_un.n_name); + } +} + + +int +valuecompare (sym1, sym2) + struct nlist *sym1, *sym2; +{ + if (reverse_sort) + return sym2->n_value - sym1->n_value; + else + return sym1->n_value - sym2->n_value; +} + +void +print_symbols (syms, symcount) + struct nlist *syms; + int symcount; +{ + int i; + + for (i = 0; i < symcount; i++) + print_one_symbol (&syms[i]); +} + +void +print_one_symbol (sym) + struct nlist *sym; +{ + if (file_on_each_line) + { + print_file_name (stdout); + printf (":"); + } + + if (undefined_only) + { + if (sym->n_type == N_EXT && !sym->n_value) + { + fprint_name (stdout, sym->n_un.n_name); + printf ("\n"); + } + return; + } + + if (sym->n_type & ~N_EXT || sym->n_value) + printf ("%08x ", sym->n_value); + else printf (" "); + + switch (sym->n_type) + { + case N_EXT: + if (sym->n_value) printf ("C"); + else printf ("U"); + break; + + case 0: + if (sym->n_value) printf ("c"); + else printf ("u"); + break; + + case N_ABS | N_EXT: + printf ("A"); + break; + + case N_ABS: + printf ("a"); + break; + + case N_TEXT | N_EXT: + printf ("T"); + break; + + case N_TEXT: + printf ("t"); + break; + + case N_DATA | N_EXT: + printf ("D"); + break; + + case N_DATA: + printf ("d"); + break; + + case N_BSS | N_EXT: + printf ("B"); + break; + + case N_BSS: + printf ("b"); + break; + + case N_SETV | N_EXT: + printf ("V"); + break; + + case N_SETV: + printf ("v"); + break; + + case N_SETA | N_EXT: + printf ("L"); + break; + + case N_SETA: + printf ("l"); + break; + + case N_SETT | N_EXT: + printf ("X"); + break; + + case N_SETT: + printf ("x"); + break; + + case N_SETD | N_EXT: + printf ("Z"); + break; + + case N_SETD: + printf ("z"); + break; + + case N_SETB | N_EXT: + printf ("S"); + break; + + case N_SETB: + printf ("s"); + break; + + case N_INDR | N_EXT: + printf ("I"); + break; + + case N_INDR: + printf ("i"); + break; + + case N_WARNING | N_EXT: + printf ("W"); + break; + + case N_WARNING: + printf ("w"); + break; + +#ifdef N_SECT + case N_SECT: + if (sym->n_sect == text_section) + printf ("t"); + else if (sym->n_sect == data_section) + printf ("d"); + else if (sym->n_sect == bss_section) + printf ("b"); + else + printf ("%d", sym->n_sect); + break; + + case N_SECT | N_EXT: + if (sym->n_sect == text_section) + printf ("T"); + else if (sym->n_sect == data_section) + printf ("D"); + else if (sym->n_sect == bss_section) + printf ("B"); + else + printf ("%d", sym->n_sect); + break; +#endif + + default: + { + char *s; + int i; +#ifdef __GNU_STAB__ + s = ""; + for (i = sizeof (stab_names) / sizeof (stab_names[0]) - 1; + i >= 0; i--) + { + if (stab_names[i].code + == (enum __stab_debug_code) sym->n_type) + { + s = stab_names[i].string; + break; + } + } +#else /* not __GNU_STAB__ */ + switch (sym->n_type) + { + case N_GSYM: + s = "GSYM"; + break; + case N_FNAME: + s = "FNAME"; + break; + case N_FUN: + s = "FUN"; + break; + case N_STSYM: + s = "STSYM"; + break; + case N_LCSYM: + s = "LCSYM"; + break; + case N_RSYM: + s = "RSYM"; + break; + case N_SLINE: + s = "SLINE"; + break; + case N_DSLINE: + s = "DSLINE"; + break; + case N_BSLINE: + s = "BSLINE"; + break; + case N_SSYM: + s = "SSYM"; + break; + case N_SO: + s = "SO"; + break; + case N_LSYM: + s = "LSYM"; + break; + case N_SOL: + s = "SOL"; + break; + case N_PSYM: + s = "PSYM"; + break; + case N_ENTRY: + s = "ENTRY"; + break; + case N_LBRAC: + s = "LBRAC"; + break; + case N_RBRAC: + s = "RBRAC"; + break; + case N_BCOMM: + s = "BCOMM"; + break; + case N_ECOMM: + s = "ECOMM"; + break; + case N_ECOML: + s = "ECOML"; + break; + case N_LENG: + s = "LENG"; + break; + default: + s = ""; + } +#endif /* not __GNU_STAB__ */ + /* %x treats them as unsigned anyway, so if we didn't cast + them we'd get 0xffffffff for all 1's instead of 0xff + or 0xffff. */ + printf ("- %02x %04x %5s", +#ifdef N_SECT + (unsigned char) sym->n_sect, +#else + (unsigned char) sym->n_other, +#endif + (unsigned short) sym->n_desc, s); + } + } + + printf (" "); + + if (sym->n_un.n_name) + fprint_name (stdout, sym->n_un.n_name); + + printf ("\n"); +} + +void +do_symdef_member (desc, offset, member_length) + int desc; + int offset; + int member_length; +{ + int symdef_size; + int nsymdefs; + struct symdef *symdefs; + int stringsize; + char *strings; + int i; + char *member_name; + int member_offset; + + /* read the string-table-length out of the file */ + + lseek (desc, offset, 0); + if (sizeof symdef_size != read (desc, &symdef_size, sizeof symdef_size)) + { + error_with_file ("premature eof in "); + return; + } + + if (symdef_size < 0) + { + error_with_file ("invalid size value in "); + return; + } + + nsymdefs = symdef_size / sizeof (struct symdef); + symdefs = (struct symdef *) alloca (symdef_size); + if (symdef_size != read (desc, symdefs, symdef_size)) + { + error_with_file ("premature eof in "); + return; + } + + if (stringsize < 0) + { + error_with_file ("invalid size value in "); + return; + } + + if (sizeof stringsize != read (desc, &stringsize, sizeof stringsize)) + { + error_with_file ("premature eof in "); + return; + } + + strings = (char *) alloca (stringsize); + if (stringsize != read (desc, strings, stringsize)) + { + error_with_file ("premature eof in "); + return; + } + + if (stringsize + symdef_size + sizeof stringsize + sizeof symdef_size != member_length) + { + error_with_file ("size of data isn't what the data calls for in "); + return; + } + + if (!file_on_each_line && (number_of_files > 1 || input_member)) + printf ("\n%s:\n", input_member ? input_member : input_name); + + member_offset = -1; + for (i = 0; i < nsymdefs; i++) + { + if (symdefs[i].stringoffset < 0 || symdefs[i].stringoffset >= stringsize) + { + error_with_file ("invalid entry in "); + return; + } + if (member_offset != symdefs[i].offset) + { + member_offset = symdefs[i].offset; + decode_library_subfile (desc, member_offset, &member_name); + } + if (file_on_each_line) + { + print_file_name (stdout); + printf (":"); + } + printf ("%s in %s\n", symdefs[i].stringoffset + strings, member_name); + } +} + +/* Report a fatal error. + STRING is a printf format string and ARG is one arg for it. */ + +void +fatal (string, arg) + char *string, *arg; +{ + fprintf (stderr, "%s: ", program_name); + fprintf (stderr, string, arg); + fprintf (stderr, "\n"); + exit (1); +} + +/* Report a nonfatal error. + STRING is a printf format string and ARG is one arg for it. */ + +void +error (string, arg) + char *string, *arg; +{ + fprintf (stderr, "%s: ", program_name); + fprintf (stderr, string, arg); + fprintf (stderr, "\n"); +} + +/* Report a nonfatal error. + STRING is printed, followed by the current file name. */ + +void +error_with_file (string) + char *string; +{ + fprintf (stderr, "%s: ", program_name); + fprintf (stderr, string); + print_file_name (stderr); + fprintf (stderr, "\n"); +} + +/* Report a fatal error using the message for the last failed system call, + followed by the string NAME. */ + +void +perror_name (name) + char *name; +{ + extern int errno, sys_nerr; + extern char *sys_errlist[]; + char *s; + + if (errno < sys_nerr) + s = concat ("", sys_errlist[errno], " for %s"); + else + s = "cannot open %s"; + error (s, name); +} + +/* Like malloc but get fatal error if memory is exhausted. */ + +char * +xmalloc (size) + unsigned size; +{ + char *result = malloc (size); + + if (!result) + fatal ("virtual memory exhausted", 0); + return result; +} + +/* Like realloc but get fatal error if out of memory. */ + +char * +xrealloc (p, size) + char *p; + unsigned size; +{ + char *result = realloc(p, size); + + if (!result) + fatal ("virtual memory exhausted", 0); + return result; +} + +/* Return a newly-allocated string + whose contents concatenate those of S1, S2, S3. */ + +char * +concat (s1, s2, s3) + char *s1, *s2, *s3; +{ + int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3); + char *result = (char *) xmalloc (len1 + len2 + len3 + 1); + + strcpy (result, s1); + strcpy (result + len1, s2); + strcpy (result + len1 + len2, s3); + result[len1 + len2 + len3] = 0; + + return result; +} + +#ifdef USG + +getpagesize () +{ + return (4096); +} + +#endif |
