add directory gnu

This commit is contained in:
gohigh
2024-02-19 00:24:47 -05:00
parent 32616db5a4
commit a40f4cadb0
5086 changed files with 1860970 additions and 0 deletions

View File

@@ -0,0 +1,212 @@
Thu Dec 29 01:48:03 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu)
* ld.c, ar.c: Don't define COFF_ENCAPSULATE automatically.
The recommended Makefile change defines it.
* ld.c (alloca): If compiling with GCC, use __builtin_alloca.
* robotussin.c: New reformatted version with all variables renamed.
* ranlib.c: New file, just runs `ar rs' on each specified file.
* Makefile: Special hack to tell ranlib where to find GNU ar.
(LIBS): Recommend -lPW on USG; ld needs it for alloca (if not GCC).
Sat Dec 24 13:59:09 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu)
* ld.c (error): Start with name of program running.
(main): Set `progname' to that name.
(digest_symbols): Fix punctuation and spelling in calls to `error'.
Tue Dec 20 21:49:46 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu)
* robotussin.c (INPUT_MAGIC): New macro, has the magic number
to expect in input files.
(nounderscore): New macro; as in ld, define it to inhibit
adding underscore to symbols.
* Makefile: Don't compile objdump on BSD; N_DATADDR causes trouble.
Tue Dec 20 14:57:38 1988 Pace Willisson (pace at prep.at.mit.edu)
* objdump.c: New program like the system 5 'dump' program.
Documentation will follow...
* Makefile: Set up CFLAGS for USG systems. Added target
libc.a to do robotussin conversion. Added objdump.
* libconvert: Wrote shell script to do robotussin conversion.
* ar.c, ld.c: Don't define COFF_ENCAPSULATE if it is already defined.
* ld.c: If i386, set a_machtype to M_386. Use a_flags instead
of a_encap. Don't compute coff header if it isn't going to
get written out.
* robotussin.c: Define COFF_ENCAPSULATE. Include a.out.encap.h
instead of a.out.h. Check magic number of input
file. Skip over optional header, if present. Don't ignore
symbols with aux entries (they could be function definitions),
instead, ignore symbols beginning with '.' (.text, etc).
Don't prepend underscore to externals, since gcc doesn't do
it now. Don't run past the end of symbols that are exactly
eight characters long. Always write the string table size,
even if it is empty. Change relocation types handled from
R_PCRBYTE, etc, to R_DIR32 and R_PCRLONG (these are the
only two emitted by the system 5 assembler.)
* size.c: Include <sys/types.h> so including sys/file.h will
not get an error on USG systems. Include fcntl.h on usg systems.
* strip.c: Move inclusion of file.h to after types.h. Include
fcntl.h. Add defintion of rename.
Fri Dec 16 13:55:11 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu)
* size.c: Delete all ROBOTUSSIN conditionals and contents.
Change SYSV conditionals to USG.
COFF_ENCAPSULATE conditionals for headers.
(do_one_file, read_header): Skip encapsulation headers if any.
* strip.c: Delete all ROBOTUSSIN conditionals and contents.
Change SYSV conditionals to USG.
COFF_ENCAPSULATE conditionals for headers.
(file_open, read_header): Skip encapsulation headers if any.
* strip.c: Change most fatal errors to nonfatal.
(file_open, read_header, read_{file,entry}_symbols):
Now return 0 for success, -1 for failure.
Failure means do no more for the current file.
(modify_relocation): Now just warn if strip a symbol needed
for relocation, and warn only once per file.
(error_with_file): New function, replaces most fatal_with_file.
Print filename first, as in most programs.
(fatal_with_file): Deleted.
(rewrite_file_symbols): Use perror_file when system call fails.
Tue Dec 13 17:16:39 1988 Jay Fenlason (hack at apple-gunkies.ai.mit.edu)
* ar.c: Changed pad character after odd-length archive member
from \0 to \n so archives can be cmp'd with the output from /bin/ar
Added fix for when ranlib is using ar to insert an __.SYMDEF member
Tue Dec 13 09:09:27 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu)
* ar.c: conditional #includes for USG.
* COFF_ENCAPSULATE conditionals for headers.
(extract_member): Don't do fchmod if USG.
Alternate USG code to set modtimes of extracted members.
(write_archive): Don't do fsync if USG.
(make_new_symdefs): Skip encapsulation headers if any.
[USG] (bcopy, bzero, bcmp): New fns.
* nm.c: Delete all ROBOTUSSIN conditionals and contents.
Include types.h.
Change SYSV conditionals to USG.
* COFF_ENCAPSULATE conditionals for headers.
(do_one_file): Skip encapsulation headers if any.
(read_header): Likewise.
* ld.c: Delete all ROBOTUSSIN conditionals and contents.
Change SYSV conditionals to USG.
Change HEADER_TYPE back to `struct exec'.
(L_SET): Define it if headers don't.
* COFF_ENCAPSULATE conditionals for headers.
(main): Update text_size differently if encapsulating.
(write_header): Write the encapsulation headers if nec.
Don't end with padding if encapsulation being done.
[USG] (bzero, bcopy, getpagesize): New fns.
Tue Dec 6 13:26:56 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu)
* ld.c (do_file_warnings): Ignored text relocation entries that
went through local symbols; any problems with lack of definitions
etc. with them would have been caught by the compiler.
Mon Dec 5 16:13:22 1988 Jay Fenlason (hack at sugar-bombs.ai.mit.edu)
* ar.c (make_new_symdefs): On error, close the input files.
Thu Nov 10 18:15:07 1988 Randall Smith (randy at apple-gunkies.ai.mit.edu)
* ld.c: Put declaration of alloca inside an #ifdef so that it
wouldn't mess up on the sparc.
* ld.c: Added #define CORE_ADDR for include of symseg.h from gdb
and took out TARGET == SUN2 for sun2 INITIALIZE_HEADER.
Wed Nov 2 18:43:09 1988 Randall Smith (randy at gluteus.ai.mit.edu)
* ld.c: Merged in isi68k port. This included a kludge for symbols
starting with _$ (#ifdef DOLLAR_KLUDGE) and addition of the
STANDARD_SEARCH_DIRS macro to override the default if it's
defined.
* ld.c: Added code for the N_WARNING symbol type. If a reference
is found to a symbol in an input .o file which contains an
N_WARNING symbol, a warning message (the name of the N_WARNING
symbol) is printed. This name is treated as a printf format
string; the name of the symbol referenced (which caused the
warning) is supplied as a single argument to the print which
interpets this string.
Tue Nov 1 16:57:00 1988 Randall Smith (randy at gluteus.ai.mit.edu)
* ld.c: Added code for Sun 2.
* ld.c: Modified access to the relocation information to be *much*
more general; added in sparc support. This change is a minor
performance hit; the perform_relocation routine uses about 0.1
seconds more time on linking gdb than did the original ld.
(perform_relocation is about 5% of the total time the loader
spends). The price of generality.
Thu Aug 4 13:20:50 1988 Randy Smith (randy at rice-chex.ai.mit.edu)
* Modified ld.c to print only the first 10 unresolved references
for each symbol, followed by a message indicating that there are
more unresolved references that have not been printed (if indeed
there are). Made default behaivior upon errors *not* writing any
output file at all. Also added the -noinhibit-exec flag to force
writing of an executable when that was desirable.
Tue Aug 2 12:04:01 1988 Randy Smith (randy at rice-chex.ai.mit.edu)
* Modified ld.c to give line numbers wherever possible on
unreferenced symbols. Added a new symbol (N_DSLNE) to allow for
the same mapping of data location to line number as is done for
text segments by N_SLINE. Added code to sort the relocation
entries when it is necessary to output these line numbers. The
assumption was made that both N_SLINE and N_DSLNE symbols would
always be in order by address.
Wed Jul 27 15:13:08 1988 Randy Smith (randy at rice-chex.ai.mit.edu)
* Modified ld.c to include a facility for equivalencing two
symbols (translating one to another). Modified lib/a.out.h to
include a definition of this new symbol. Modified nm.c to
recognize this symbol and all of the set element and vector
symbols I had added before.
Thu Jul 21 17:06:10 1988 Randy Smith (randy at rice-chex.ai.mit.edu)
* Modified ld.c to printout source file and line numbers for
unresolved references whenever possible (ie. whenever the input
file has debugger symbols and the reference is from the text area).
Wed Jul 13 17:21:33 1988 Randy Smith (randy at frosted-flakes.ai.mit.edu)
* Modified ld.c and a.out.h to handle new types of symbols; the
loader can now create "sets" of symbols from entries in its input
files. See a.out.h for more info. Also fixed a bug in ld in
which references to common areas that we not defined in one pass
of the loader caused errors on the next.
Sat Jul 2 00:05:44 1988 Richard Stallman (rms at sugar-bombs.ai.mit.edu)
* ld.c (symdef_library): Error check was off by one.
Mon May 9 12:53:08 1988 Chris Hanson (cph at kleph)
* ar.c (replace_members): After updating map, write out
`change_map->next' rather than `map', since the latter may be
null.

View File

@@ -0,0 +1,68 @@
# Makefile for GNU binary-file utilities
# select a set of CFLAGS and PROGS, below, depending on the system type
GNUCC = gcc -O
# for BSD systems
CFLAGS = -g
# Don't add robotussin; it won't compile on BSD or GNU systems.
# objdump also won't compile on most systems (trouble with N_DATADDR).
PROGS = gprof ld size nm strip ar ranlib
# for USG systems using COFF_ENCAPSULATE
# also, you will want to make the target libc.a (but it takes a long time)
# Note that you should leave a copy of `ar' in this directory
# after you install it, since `ranlib' will try to run it from here.
#CFLAGS = -g -DUSG -DCOFF_ENCAPSULATE -DPORTAR -DNON_NATIVE -Dnounderscore
#PROGS = ld size nm strip ar robotussin objdump ranlib
#LIBS = -lPW
all: $(PROGS)
ld: ld.o
# LIBS is used here since ld needs to use alloca.
# Alternatively, compile it with GNU C--then the compiler handles alloca.
$(CC) -o ld ld.o $(LIBS)
size: size.o
$(CC) -o size size.o
nm: nm.o
$(CC) -o nm nm.o
strip: strip.o
$(CC) -o strip strip.o
ar: ar.o
$(CC) -o ar ar.o
gprof: gprof.o
$(GNUCC) -o gprof gprof.o
gprof.o: gprof.c gmon.h
$(GNUCC) -c $(CFLAGS) gprof.c
ranlib: ranlib.o
$(CC) -o ranlib ranlib.o
ranlib.o: ranlib.c
$(CC) -c -g -DAR_PROG=\"`pwd`/ar\" ranlib.c
# Robotussin is NOT part of `all'.
robotussin: robotussin.o
$(CC) -o robotussin robotussin.o
libc.a: robotussin libconvert
libconvert
rm -rf tmp
clean:
-rm -f *.o core
-rm -f gprof ar nm size strip ld robotussin objdump ranlib
dist:
-rm -rf binutils
mkdir binutils
-ln * binutils
(cd binutils; rm -f GNUmakefile *~ "#*" log* binutils.tar*; make clean)
tar cof binutils.tar binutils
compress < binutils.tar > binutils.tar.Z
rm -rf binutils

View File

@@ -0,0 +1,37 @@
These files are some GNU utilities for operating on binary files.
Note that GNU make, which used to be included here, is now distributed
in a separate tar file.
Report bugs in these programs to bug-gnu-utils@prep.ai.mit.edu and use
the date of the main source file as a "version number" for the
program.
Define USG with `-DUSG' when compiling these programs to run on system V.
COFF is not supported, but we do support a way of encapsulating GNU
executable files with COFF headers. Use -DCOFF_ENCAPSULATE when you
compile, to enable this feature.
In order to use encapsulation, you must use entirely GNU tools,
including these plus GAS, GCC and GDB. You will need to convert the
system libraries to BSD object file format. Use the shell script
libconvert (which uses robotussin) for that.
The GNU version of ld has some interesting features:
1. Undefined and multiply-defined global symbol errors
are now associated with specific source files and line numbers,
and printed in a format M-x next-error can parse.
2. Normally no output is written if there are serious errors.
Use the option `-noinhibit-exec' if you want an output file anyway.
3. Global symbols can be defined by indirection to other symbols.
See comments at definition of N_INDR in ld.c
4. LD can accumulate sets of related values from all the object files
that are being linked together, and put them into a vector that can
be accessed at run time. Thus, you can arrange for each file to have
initializations to be run when your `main' function sees fit, without
having to know the names of all the files that are linked together.
See comments at definition of N_SETA, etc., in ld.c.

View File

@@ -0,0 +1,115 @@
/* this file can be renamed 'a.out.h' someday */
/*
* another try at encapsulating bsd object files in coff
* by Pace Willisson 12/9/88
*
* This time, we will only use the coff headers to tell the kernel
* how to exec the file. Therefore, the only fields that need to
* be filled in are the scnptr and vaddr for the text and data
* sections, and the vaddr for the bss. As far as coff is concerned,
* there is no symbol table, relocation, or line numbers.
*
* A normal bsd header (struct exec) is placed after the coff headers,
* and before the real text. I defined a the new fields 'a_machtype'
* and a_flags. If a_machtype is M_386, and a_flags & A_ENCAP is
* true, then the bsd header is preceeded by a coff header. Macros
* like N_TXTOFF and N_TXTADDR use this field to find the bsd header.
*
* The only problem is to track down the bsd exec header. The
* macros HEADER_OFFSET, etc do this. Look at nm.c, dis.c, etc
* for examples.
*/
#include "a.out.gnu.h"
#define A_ENCAP 1 /* when true in a_flags, coff header preceeds bsd header */
/* Describe the COFF header used for encapsulation. */
struct coffheader
{
/* filehdr */
unsigned short f_magic;
unsigned short f_nscns;
long f_timdat;
long f_symptr;
long f_nsyms;
unsigned short f_opthdr;
unsigned short f_flags;
/* aouthdr */
short magic;
short vstamp;
long tsize;
long dsize;
long bsize;
long entry;
long text_start;
long data_start;
struct coffscn
{
char s_name[8];
long s_paddr;
long s_vaddr;
long s_size;
long s_scnptr;
long s_relptr;
long s_lnnoptr;
unsigned short s_nreloc;
unsigned short s_nlnno;
long s_flags;
} scns[3];
};
/* Describe some of the parameters of the encapsulation,
including how to find the encapsulated BSD header. */
#ifdef i386
#define COFF_MAGIC 0514 /* I386MAGIC */
#endif
#if defined(i386)
short __header_offset_temp;
#define HEADER_OFFSET(f) \
(__header_offset_temp = 0, \
fread ((char *)&__header_offset_temp, sizeof (short), 1, (f)), \
fseek ((f), -sizeof (short), 1), \
__header_offset_temp==COFF_MAGIC ? sizeof(struct coffheader) : 0)
#define HEADER_OFFSET_FD(fd) \
(__header_offset_temp = 0, \
read ((fd), (char *)&__header_offset_temp, sizeof (short)), \
lseek ((fd), -sizeof (short), 1), \
__header_offset_temp==COFF_MAGIC ? sizeof(struct coffheader) : 0)
#else
#define HEADER_OFFSET(f) 0
#define HEADER_OFFSET_FD(fd) 0
#endif
#define HEADER_SEEK(f) (fseek ((f), HEADER_OFFSET((f)), 1))
#define HEADER_SEEK_FD(fd) (lseek ((fd), HEADER_OFFSET_FD((fd)), 1))
/* Describe the characteristics of the BSD header
that appears inside the encapsulation. */
#undef N_BADMAG
#define N_BADMAG(x) \
(((x).a_magic)!=OMAGIC && ((x).a_magic)!=ZMAGIC)
#undef _N_HDROFF
#undef N_TXTADDR
#undef N_DATADDR
/* always 0 on real bsd systems */
#define _N_HDROFF(x) ((x).a_flags & A_ENCAP ? sizeof (struct coffheader) : 0)
/* Address of text segment in memory after it is loaded. */
#define N_TXTADDR(x) \
(((x).a_flags & A_ENCAP) ? \
sizeof (struct coffheader) + sizeof (struct exec) : 0)
#define SEGMENT_SIZE 0x400000
#define N_DATADDR(x) \
(((x).a_flags & A_ENCAP) ? \
(SEGMENT_SIZE + ((N_TXTADDR(x)+(x).a_text-1) & ~(SEGMENT_SIZE-1))) : \
(N_TXTADDR(x)+(x).a_text))

View File

@@ -0,0 +1,155 @@
struct exec
{
#ifdef COFF_ENCAPSULATE
unsigned short a_magic;
unsigned char a_machtype;
unsigned char a_flags;
#else
long a_magic; /* number identifies as .o file and gives type of such. */
#endif
unsigned a_text; /* length of text, in bytes */
unsigned a_data; /* length of data, in bytes */
unsigned a_bss; /* length of uninitialized data area for file, in bytes */
unsigned a_syms; /* length of symbol table data in file, in bytes */
unsigned a_entry; /* start address */
unsigned a_trsize; /* length of relocation info for text, in bytes */
unsigned a_drsize; /* length of relocation info for data, in bytes */
};
/* these go in the a_machtype field */
#define M_68010 1 /* sun defined these */
#define M_68020 2
#define M_386 100 /* skip a bunch so we don't conflict with sun's numbers */
/* Code indicating object file or impure executable. */
#define OMAGIC 0407
/* Code indicating pure executable. */
#define NMAGIC 0410
/* Code indicating demand-paged executable. */
#define ZMAGIC 0413
#define N_BADMAG(x) \
(((x).a_magic) != OMAGIC && ((x).a_magic) != NMAGIC \
&& ((x).a_magic) != ZMAGIC)
#define _N_HDROFF(x) (1024 - sizeof (struct exec))
#define N_TXTOFF(x) \
((x).a_magic == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : sizeof (struct exec))
#define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text)
#define N_TRELOFF(x) (N_DATOFF(x) + (x).a_data)
#define N_DRELOFF(x) (N_TRELOFF(x) + (x).a_trsize)
#define N_SYMOFF(x) (N_DRELOFF(x) + (x).a_drsize)
#define N_STROFF(x) (N_SYMOFF(x) + (x).a_syms)
/* Address of text segment in memory after it is loaded. */
#define N_TXTADDR(x) 0
/* Address of data segment in memory after it is loaded.
Note that it is up to you to define SEGMENT_SIZE
on machines not listed here. */
#ifdef vax
#define SEGMENT_SIZE page_size
#endif
#ifdef is68k
#define SEGMENT_SIZE 0x20000
#endif
#ifndef N_DATADDR
#define N_DATADDR(x) \
(((x).a_magic==OMAGIC)? (N_TXTADDR(x)+(x).a_text) \
: (SEGMENT_SIZE + ((N_TXTADDR(x)+(x).a_text-1) & ~(SEGMENT_SIZE-1))))
#endif
/* Address of bss segment in memory after it is loaded. */
#define N_BSSADDR(x) (N_DATADDR(x) + (x).a_data)
struct nlist {
union {
char *n_name;
struct nlist *n_next;
long n_strx;
} n_un;
char n_type;
char n_other;
short n_desc;
unsigned n_value;
};
#define N_UNDF 0
#define N_ABS 2
#define N_TEXT 4
#define N_DATA 6
#define N_BSS 8
#define N_FN 15
#define N_EXT 1
#define N_TYPE 036
#define N_STAB 0340
/* 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. */
#define N_INDR 0xa
/* 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_TEXT global symbol
in that it can satisfy undefined external references. */
/* These appear as input to LD, in a .o file. */
#define N_SETA 0x14 /* Absolute set element symbol */
#define N_SETT 0x16 /* Text set element symbol */
#define N_SETD 0x18 /* Data set element symbol */
#define N_SETB 0x1A /* Bss set element symbol */
/* This is output from LD. */
#define N_SETV 0x1C /* Pointer to set vector in text area. */
/* This structure describes a single relocation to be performed.
The text-relocation section of the file is a vector of these structures,
all of which apply to the text section.
Likewise, the data-relocation section applies to the data section. */
struct relocation_info
{
/* Address (within segment) to be relocated. */
int r_address;
/* The meaning of r_symbolnum depends on r_extern. */
unsigned int r_symbolnum:24;
/* Nonzero means value is a pc-relative offset
and it should be relocated for changes in its own address
as well as for changes in the symbol or section specified. */
unsigned int r_pcrel:1;
/* Length (as exponent of 2) of the field to be relocated.
Thus, a value of 2 indicates 1<<2 bytes. */
unsigned int r_length:2;
/* 1 => relocate with value of symbol.
r_symbolnum is the index of the symbol
in file's the symbol table.
0 => relocate with the address of a segment.
r_symbolnum is N_TEXT, N_DATA, N_BSS or N_ABS
(the N_EXT bit may be set also, but signifies nothing). */
unsigned int r_extern:1;
/* Four bits that aren't used, but when writing an object file
it is desirable to clear them. */
unsigned int r_pad:4;
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,48 @@
/* Format of gmon.out file. */
/* This header appears at the beginning of the gmon.out file.
LOW and HIGH are low and high water marks for the program counter
during the creation of the gmon.out file.
LOW is also the offset where the histogram table starts in the
text (code) segment.
NBYTES is the number of bytes in this header plus the histogram itself,
which immediately follows the header in the file.
Therefore, the number of histogram entries is
(NBYTES - sizeof (struct gm_header)) / (sizeof (CHUNK)).
Each entry applies to a range of PC values.
The first entry applies to PC values starting at LOW.
The last entry applies to PC values ending at HIGH.
Therefore, the span of each entry's range is
(HIGH - LOW) / number-of-entries
Usually this value is 4.
*/
struct gm_header {
unsigned long low;
unsigned long high;
long nbytes;
};
/* Data type of an entry in the PC histogram. */
#define CHUNK short
/* After the histogram cone the function call count entries.
They fill all the rest of the file.
Each count entry records the number of calls to one function
from one pc value.
FROM describes the caller pc, as an offset into the text segment.
TO is the address of the called function.
NCALLS is the number of calls counted from FROM to TO.
Note that if a function A is called from several places in B,
there are separate call count entries for each call, with different FROM.
All of them together count the number of calls from B to A. */
struct gm_call {
unsigned long from;
unsigned long to;
unsigned long ncalls;
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,933 @@
\input texinfo @c -*-texinfo-*-
@setfilename gprof
@settitle gprof
@ifinfo
This file documents the gprof profiler of the GNU system.
Copyright (C) 1988 Free Software Foundation, Inc.
Permission is granted to make and distribute verbatim copies of
this manual provided the copyright notice and this permission notice
are preserved on all copies.
@ignore
Permission is granted to process this file through Tex and print the
results, provided the printed document carries copying permission
notice identical to this one except for the removal of this paragraph
(this paragraph not being relevant to the printed manual).
@end ignore
Permission is granted to copy and distribute modified versions of this
manual under the conditions for verbatim copying, provided that the entire
resulting derived work is distributed under the terms of a permission
notice identical to this one.
Permission is granted to copy and distribute translations of this manual
into another language, under the above conditions for modified versions.
@end ifinfo
@titlepage
@center @titlefont{gprof}
@sp 1
@center The GNU Profiler
@sp 2
@center Jay Fenlason and Richard Stallman
@sp 4
This manual describes the GNU profiler, @code{gprof}, and how you can use
it to determine which parts of a program are taking most of the execution
time. We assume that you know how to write, compile, and execute programs.
GNU @code{gprof} was written by Jay Fenlason.
@sp 8
Copyright @copyright{} 1988 Free Software Foundation, Inc.
Permission is granted to make and distribute verbatim copies of
this manual provided the copyright notice and this permission notice
are preserved on all copies.
@ignore
Permission is granted to process this file through Tex and print the
results, provided the printed document carries copying permission
notice identical to this one except for the removal of this paragraph
(this paragraph not being relevant to the printed manual).
@end ignore
Permission is granted to copy and distribute modified versions of this
manual under the conditions for verbatim copying, provided that the entire
resulting derived work is distributed under the terms of a permission
notice identical to this one.
Permission is granted to copy and distribute translations of this manual
into another language, under the same conditions as for modified versions.
@end titlepage
@ifinfo
@node Top, Why, Top, (dir)
@ichapter Profiling a Program: Where Does It Spend Its Time?
This manual describes the GNU profiler @code{gprof}, and how you can use it
to determine which parts of a program are taking most of the execution
time. We assume that you know how to write, compile, and execute programs.
GNU @code{gprof} was written by Jay Fenlason.
@menu
* Why:: What profiling means, and why it is useful.
* Compiling:: How to compile your program for profiling.
* Executing:: How to execute your program to generate the
profile data file @file{gmon.out}.
* Analyzing:: How to run @code{gprof}, and how to specify
options for it.
* Flat Profile:: The flat profile shows how much time was spent
executing directly in each function.
* Call Graph:: The call graph shows which functions called which
others, and how much time each function used
when its subroutine calls are included.
* Implementation:: How the profile data is recorded and written.
* Sampling Error:: Statistical margins of error.
How to accumulate data from several runs
to make it more accurate.
* Assumptions:: Some of @code{gprof}'s measurements are based
on assumptions about your program
that could be very wrong.
* Incompatibilities:: (between GNU @code{gprof} and Unix @code{gprof}.)
@end menu
@end ifinfo
@node Why, Compiling, Top, Top
@chapter Why Profile
Profiling allows you to learn where your program spent its time and which
functions called which other functions while it was executing. This
information can show you which pieces of your program are slower than you
expected, and might be candidates for rewriting to make your program
execute faster. It can also tell you which functions are being called more
or less often than you expected. This may help you spot bugs that had
otherwise been unnoticed.
Since the profiler uses information collected during the actual execution
of your program, it can be used on programs that are too large or too
complex to analyze by reading the source. However, how your program is run
will affect the information that shows up in the profile data. If you
don't use some feature of your program while it is being profiled, no
profile information will be generated for that feature.
Profiling has several steps:
@itemize @bullet
@item
You must compile and link your program with profiling enabled.
@xref{Compiling}.
@item
You must execute your program to generate a profile data file.
@xref{Executing}.
@item
You must run @code{gprof} to analyze the profile data.
@xref{Analyzing}.
@end itemize
The next three chapters explain these steps in greater detail.
The result of the analysis is a file containing two tables, the
@dfn{flat profile} and the @dfn{call graph} (plus blurbs which briefly
explain the contents of these tables).
The flat profile shows how much time your program spent in each function,
and how many times that function was called. If you simply want to know
which functions burn most of the cycles, it is stated concisely here.
@xref{Flat Profile}.
The call graph, shows, for each function, which functions called it, which
other functions it called, and how many times. There is also an estimate
of how much time was spent in the subroutines of each function. This can
suggest places where you might try to eliminate function calls that use a
lot of time. @xref{Call Graph}.
@node Compiling, Executing, Why, Top
@chapter Compiling a Program for Profiling
The first step in generating profile information for your program is
to compile and link it with profiling enabled.
To compile a source file for profiling, specify the @samp{-pg} option when
you run the compiler. (This is in addition to the options you normally
use.)
To link the program for profiling, if you use a compiler such as @code{cc}
to do the linking, simply specify @samp{-pg} in addition to your usual
options. The same option, @samp{-pg}, alters either compilation or linking
to do what is necessary for profiling. Here are examples:
@example
cc -g myprog.c utils.c -pg
cc -o myprog myprog.o utils.o -pg
@end example
The @samp{-pg} option also works with a command that both compiles and links:
@example
cc -o myprog myprog.c utils.c -g -pg
@end example
If you run the linker @code{ld} directly instead of through a compiler such
as @code{cc}, you must specify the profiling startup file
@file{/lib/gcrt0.o} as the first input file instead of the usual startup
file @file{/lib/crt0.o}. In addition, you would probably want to specify
the profiling C library, @file{/usr/lib/libc_p.a}, by writing @samp{-lc_p}
instead of the usual @samp{-lc}. This is not absolutely necessary, but doing
this gives you number-of-calls information for standard library functions such
as @code{read} and @code{open}. For example:
@example
ld -o myprog /lib/gcrt0.o myprog.o utils.o -lc_p
@end example
If you compile only some of the modules of the program with @samp{-pg}, you
can still profile the program, but you won't get complete information about
the modules that were compiled without @samp{-pg}. The only information
you get for the functions in those modules is the total time spent in them;
there is no record of how many times they were called, or from where. This
will not affect the flat profile (except that the @code{calls} field for
the functions will be blank), but will greatly reduce the usefulness of the
call graph.
So far GNU @code{gprof} has been tested only with C programs, but it ought
to work with any language in which programs are compiled and linked to form
executable files. If it does not, please let us know.
@node Executing, Analyzing, Compiling, Top
@chapter Executing the Program to Generate Profile Data
Once the program is compiled for profiling, you must run it in order to
generate the information that @code{gprof} needs. Simply run the program
as usual, using the normal arguments, file names, etc. The program should
run normally, producing the same output as usual. It will, however, run
somewhat slower than normal because of the time spent collecting and the
writing the profile data.
The way you run the program---the arguments and input that you give
it---may have a dramatic effect on what the profile information shows. The
profile data will describe the parts of the program that were activated for
the particular input you use. For example, if the first command you give
to your program is to quit, the profile data will show the time used in
initialization and in cleanup, but not much else.
You program will write the profile data into a file called @file{gmon.out}
just before exiting. If there is already a file called @file{gmon.out},
its contents are overwritten. There is currently no way to tell the
program to write the profile data under a different name, but you can rename
the file afterward if you are concerned that it may be overwritten.
In order to write the @file{gmon.out} file properly, your program must exit
normally: by returning from @code{main} or by calling @code{exit}. Calling
the low-level function @code{_exit} does not write the profile data, and
neither does abnormal termination due to an unhandled signal.
The @file{gmon.out} file is written in the program's @emph{current working
directory} at the time it exits. This means that if your program calls
@code{chdir}, the @file{gmon.out} file will be left in the last directory
your program @code{chdir}'d to. If you don't have permission to write in
this directory, the file is not written. You may get a confusing error
message if this happens. (We have not yet replaced the part of Unix
responsible for this; when we do, we will make the error message
comprehensible.)
@node Analyzing, Flat Profile, Executing, Top
@chapter Analyzing the Profile Data: @code{gprof} Command Summary
After you have a profile data file @file{gmon.out}, you can run @code{gprof}
to interpret the information in it. The @code{gprof} program prints a
flat profile and a call graph on standard output. Typically you would
redirect the output of @code{gprof} into a file with @samp{>}.
You run @code{gprof} like this:
@example
gprof @var{options} [@var{executable-file} [@var{profile-data-files}@dots{}]] [> @var{outfile}]
@end example
@noindent
Here square-brackets indicate optional arguments.
If you omit the executable file name, the file @file{a.out} is used. If
you give no profile data file name, the file @file{gmon.out} is used. If
any file is not in the proper format, or if the profile data file does not
appear to belong to the executable file, an error message is printed.
You can give more than one profile data file by entering all their names
after the executable file name; then the statistics in all the data files
are summed together.
The following options may be used to selectively include or exclude
functions in the output:
@table @code
@item -a
The @code{-a} option causes @code{gprof} to ignore static (private)
functions. (These are functions whose names are not listed as global,
and which are not visible outside the file/function/block where they
were defined.) Time spent in these functions, calls to/from them,
etc, will all be attributed to the function that was loaded directly
before it in the executable file. This is compatible with Unix
@code{gprof}, but a bad idea. This option affects both the flat
profile and the call graph.
@item -e @var{function_name}
The @code{-e @var{function}} option tells @code{gprof} to not print
information about the function (and its children@dots{}) in the call
graph. The function will still be listed as a child of any functions
that call it, but its index number will be shown as @samp{[not
printed]}.
@item -E @var{function_name}
The @code{-E @var{function}} option works like the @code{-e} option,
but time spent in the function (and children who were not called from
anywhere else), will not be used to compute the percentages-of-time
for the call graph.
@item -f @var{function_name}
The @code{-f @var{function}} option causes @code{gprof} to limit the
call graph to the function and its children (and their
children@dots{}).
@item -F @var{function_name}
The @code{-F @var{function}} option works like the @code{-f} option,
but only time spent in the function and its children (and their
children@dots{}) will be used to determine total-time and
percentages-of-time for the call graph.
@item -z
If you give the @code{-z} option, @code{gprof} will mention all
functions in the flat profile, even those that were never called, and
that had no time spent in them.
@end table
The order of these options does not matter.
Note that only one function can be specified with each @code{-e},
@code{-E}, @code{-f} or @code{-F} option. To specify more than one
function, use multiple options. For example, this command:
@example
gprof -e boring -f foo -f bar myprogram > gprof.output
@end example
@noindent
lists in the call graph all functions that were reached from either
@code{foo} or @code{bar} and were not reachable from @code{boring}.
There are two other useful @code{gprof} options:
@table @code
@item -b
If the @code{-b} option is given, @code{gprof} doesn't print the
verbose blurbs that try to explain the meaning of all of the fields in
the tables. This is useful if you intend to print out the output, or
are tired of seeing the blurbs.
@item -s
The @code{-s} option causes @code{gprof} to summarize the information
in the profile data files it read in, and write out a profile data
file called @file{gmon.sum}, which contains all the information from
the profile data files that @code{gprof} read in. The file @file{gmon.sum}
may be one of the specified input files; the effect of this is to
merge the data in the other input files into @file{gmon.sum}.
@xref{Sampling Error}.
Eventually you can run @code{gprof} again without @samp{-s} to analyze the
cumulative data in the file @file{gmon.sum}.
@end table
@node Flat Profile, Call Graph, Analyzing, Top
@chapter How to Understand the Flat Profile
@cindex flat profile
The @dfn{flat profile} shows the total amount of time your program
spent executing each function. Unless the @samp{-z} option is given,
functions with no apparent time spent in them, and no apparent calls
to them, are not mentioned. Note that if a function was not compiled
for profiling, and didn't run long enough to show up on the program
counter histogram, it will be indistinguishable from a function that
was never called.
@c???
Here is a sample flat profile for a small program:
@example
Each sample counts as 0.01 seconds.
% time seconds cumsec calls function
79.17 0.19 0.19 6 a
16.67 0.04 0.23 1 main
4.17 0.01 0.24 mcount
0.00 0 0.24 1 profil
@end example
@noindent
The functions are sorted by decreasing run-time spent in them. The
functions @code{mcount} and @code{profil} are part of the profiling
aparatus and appear in every flat profile; their time gives a measure of
the amount of overhead due to profiling. (These internal functions are
omitted from the call graph.)
The sampling period estimates the margin of error in each of the time
figures. A time figure that is not much larger than this is not reliable.
In this example, the @code{seconds} field for @code{mcount} might well be 0
or 0.02 in another run. @xref{Sampling Error}, for a complete discussion.
Here is what the fields in each line mean:
@table @code
@item % time
This is the percentage of the total execution time your program spent
in this function. These should all add up to 100%.
@item seconds
This is the total number of seconds the computer spent executing the
user code of this function.
@item cumsec
This is the cumulative total number of seconds the computer spent
executing this functions, plus the time spent in all the functions
above this one in this table.
@item calls
This is the total number of times the function was called. If the
function was never called, or the number of times it was called cannot
be determined (probably because the function was not compiled with
profiling enabled), the @dfn{calls} field is blank.
@item function
This is the name of the function.
@end table
@node Call Graph, Implementation, Flat Profile, Top
@chapter How to Read the Call Graph
@cindex call graph
The @dfn{call graph} shows how much time was spent in each function
and its children. From this information, you can find functions that,
while they themselves may not have used much time, called other
functions that did use unusual amounts of time.
Here is a sample call from a small program. This call came from the
same @code{gprof} run as the flat profile example in the previous
chapter.
@example
index % time self children called name
<spontaneous>
[1] 100.00 0 0.23 0 start [1]
0.04 0.19 1/1 main [2]
----------------------------------------
0.04 0.19 1/1 start [1]
[2] 100.00 0.04 0.19 1 main [2]
0.19 0 1/1 a [3]
----------------------------------------
0.19 0 1/1 main [2]
[3] 82.61 0.19 0 1+5 a [3]
----------------------------------------
@end example
The lines full of dashes divide this table into @dfn{entries}, one for each
function. Each entry has one or more lines.
In each entry, the primary line is the one that starts with an index number
in square brackets. The end of this line says which function the entry is
for. The preceding lines in the entry describe the callers of this
function and the following lines describe its subroutines (also called
@dfn{children} when we speak of the call graph).
The entries are sorted by time spent in the function and its subroutines.
The internal profiling functions @code{mcount} and @code{profil}
(@pxref{Flat Profile}) are never mentioned in the call graph.
@menu
* Primary:: Details of the primary line's contents.
* Callers:: Details of caller-lines' contents.
* Subroutines:: Details of subroutine-lines' contents.
* Cycles:: When there are cycles of recursion,
such as @code{a} calls @code{b} calls @code{a}@dots{}
@end menu
@node Primary, Callers, Call Graph, Call Graph
@section The Primary Line
The @dfn{primary line} in a call graph entry is the line that
describes the function which the entry is about and gives the overall
statistics for this function.
For reference, we repeat the primary line from the entry for function
@code{a} in our main example, together with the heading line that shows the
names of the fields:
@example
index % time self children called name
@dots{}
[3] 82.61 0.19 0 1+5 a [3]
@end example
Here is what the fields in the primary line mean:
@table @code
@item index
Entries are numbered with consecutive integers. Each function
therefore has an index number, which appears at the beginning of its
primary line.
Each cross-reference to a function, as a caller or subroutine of
another, gives its index number as well as its name. The index number
guides you if you wish to look for the entry for that function.
@item % time
This is the percentage of the total time that was spent in this
function, including time spent in subroutines called from this
function.
The time spent in this function is counted again for the callers of
this function. Therefore, adding up these percentages is meaningless.
@item self
This is the total amount of time spent in this function. This
should be identical to the number printed in the @code{seconds} field
for this function in the flat profile.
@item children
This is the total amount of time spent in the subroutine calls made by
this function. This should be equal to the sum of all the @code{self}
and @code{children} entries of the children listed directly below this
function.
@item called
This is the number of times the function was called.
If the function called itself recursively, there are two numbers,
separated by a @samp{+}. The first number counts non-recursive calls,
and the second counts recursive calls.
In the example above, the function @code{a} called itself five times,
and was called once from @code{main}.
@item name
This is the name of the current function. The index number is
repeated after it.
If the function is part of a cycle of recursion, the cycle number is
printed between the function's name and the index number
(@pxref{Cycles}). For example, if function @code{gnurr} is part of
cycle number one, and has index number twelve, its primary line would
be end like this:
@example
gnurr <cycle 1> [12]
@end example
@end table
@node Callers, Subroutines, Primary, Call Graph
@section Lines for a Function's Callers
A function's entry has a line for each function it was called by.
These lines' fields correspond to the fields of the primary line, but
their meanings are different because of the difference in context.
For reference, we repeat two lines from the entry for the function
@code{a}, the primary line and one caller-line preceding it, together
with the heading line that shows the names of the fields:
@example
index % time self children called name
@dots{}
0.19 0 1/1 main [2]
[3] 82.61 0.19 0 1+5 a [3]
@end example
Here are the meanings of the fields in the caller-line for @code{a}
called from @code{main}:
@table @code
@item self
An estimate of the amount of time spent in @code{a} itself when it was
called from @code{main}.
@item children
An estimate of the amount of time spent in @code{a}'s subroutines when
@code{a} was called from @code{main}.
The sum of the @code{self} and @code{children} fields is an estimate
of the amount of time spent within calls to @code{a} from @code{main}.
@item called
Two numbers: the number of times @code{a} was called from @code{main},
followed by the total number of nonrecursive calls to @code{a} from
all its callers.
@item name and index number
The name of the caller of @code{a} to which this line applies,
followed by the caller's index number.
Not all functions have entries in the call graph; some
options to @code{gprof} request the omission of certain functions.
When a caller has no entry of its own, it still has caller-lines
in the entries of the functions it calls. Since this caller
has no index number, the string @samp{[not printed]} is used
instead of one.
If the caller is part of a recursion cycle, the cycle number is
printed between the name and the index number.
@end table
If the identity of the callers of a function cannot be determined, a
dummy caller-line is printed which has @samp{<spontaneous>} as the
``caller's name'' and all other fields blank. This can happen for
signal handlers.
@c What if some calls have determinable callers' names but not all?
@node Subroutines, Cycles, Callers, Call Graph
@section Lines for a Function's Subroutines
A function's entry has a line for each of its subroutines---in other
words, a line for each other function that it called. These lines'
fields correspond to the fields of the primary line, but their meanings
are different because of the difference in context.
For reference, we repeat two lines from the entry for the function
@code{main}, the primary line and a line for a subroutine, together
with the heading line that shows the names of the fields:
@example
index % time self children called name
@dots{}
[2] 100.00 0.04 0.19 1 main [2]
0.19 0 1/1 a [3]
@end example
Here are the meanings of the fields in the subroutine-line for @code{main}
calling @code{a}:
@table @code
@item self
An estimate of the amount of time spent directly within @code{a}
when @code{a} was called from @code{main}.
@item children
An estimate of the amount of time spent in subroutines of @code{a}
when @code{a} was called from @code{main}.
The sum of the @code{self} and @code{children} fields is an estimate
of the total time spent in calls to @code{a} from @code{main}.
@item called
Two numbers, the number of calls to @code{a} from @code{main}
followed by the total number of nonrecursive calls to @code{a}.
@item name
The name of the subroutine of @code{a} to which this line applies,
followed by the subroutine's index number. If the subroutine is
a function omitted from the call graph, it has no index number,
so @samp{[not printed]} appears instead.
If the caller is part of a recursion cycle, the cycle number is
printed between the name and the index number.
@end table
@node Cycles,, Subroutines, Call Graph
@section How Mutually Recursive Functions Are Described
@cindex cycle
@cindex recursion cycle
The graph may be complicated by the presence of @dfn{cycles of
recursion} in the call graph. A cycle exists if a function calls
another function that (directly or indirectly) calls (or appears to
call) the original function. For example: if @code{a} calls @code{b},
and @code{b} calls @code{a}, then @code{a} and @code{b} form a cycle.
Whenever there are call-paths both ways between a pair of functions, they
belong to the same cycle. If @code{a} and @code{b} call each other and
@code{b} and @code{c} call each other, all three make one cycle. Note that
even if @code{b} only calls @code{a} if it was not called from @code{a},
@code{gprof} cannot determine this, so @code{a} and @code{b} are still
considered a cycle.
The cycles are numbered with consecutive integers. When a function
belongs to a cycle, each time the function name appears in the call graph
it is followed by @samp{<cycle @var{number}>}.
The reason cycles matter is that they make the time values in the call
graph paradoxical. The ``time spent in children'' of @code{a} should
include the time spent in its subroutine @code{b} and in @code{b}'s
subroutines---but one of @code{b}'s subroutines is @code{a}! How much of
@code{a}'s time should be included in the children of @code{a}, when
@code{a} is indirectly recursive?
The way @code{gprof} resolves this paradox is by creating a single entry
for the cycle as a whole. The primary line of this entry describes the
total time spent directly in the functions of the cycle. The
``subroutines'' of the cycle are the individual functions of the cycle, and
all other functions that were called directly by them. The ``callers'' of
the cycle are the functions, outside the cycle, that called functions in
the cycle.
Here is a portion of the call graph which shows a cycle containing
functions @code{a} and @code{b}. The cycle was entered by a call to
@code{a} from @code{main}; both @code{a} and @code{b} called @code{c}.@refill
@example
index % time self children called name
----------------------------------------
1.77 0 1/1 main [2]
[3] 91.71 1.77 0 1+5 <cycle 1 as a whole> [3]
1.02 0 3 b <cycle 1> [4]
0.75 0 2 a <cycle 1> [5]
----------------------------------------
3 a <cycle 1> [5]
[4] 52.85 1.02 0 0 b <cycle 1> [4]
2 a <cycle 1> [5]
0 0 3/6 c [6]
----------------------------------------
1.77 0 1/1 main [2]
2 b <cycle 1> [4]
[5] 38.86 0.75 0 1 a <cycle 1> [5]
3 b <cycle 1> [4]
0 0 3/6 c [6]
----------------------------------------
@end example
@noindent
(The entire call graph for this program contains in addition an entry for
@code{main}, which calls @code{a}, and an entry for @code{c}, with callers
@code{a} and @code{b}.)
@example
index % time self children called name
<spontaneous>
[1] 100.00 0 1.93 0 start [1]
0.16 1.77 1/1 main [2]
----------------------------------------
0.16 1.77 1/1 start [1]
[2] 100.00 0.16 1.77 1 main [2]
1.77 0 1/1 a <cycle 1> [5]
----------------------------------------
1.77 0 1/1 main [2]
[3] 91.71 1.77 0 1+5 <cycle 1 as a whole> [3]
1.02 0 3 b <cycle 1> [4]
0.75 0 2 a <cycle 1> [5]
0 0 6/6 c [6]
----------------------------------------
3 a <cycle 1> [5]
[4] 52.85 1.02 0 0 b <cycle 1> [4]
2 a <cycle 1> [5]
0 0 3/6 c [6]
----------------------------------------
1.77 0 1/1 main [2]
2 b <cycle 1> [4]
[5] 38.86 0.75 0 1 a <cycle 1> [5]
3 b <cycle 1> [4]
0 0 3/6 c [6]
----------------------------------------
0 0 3/6 b <cycle 1> [4]
0 0 3/6 a <cycle 1> [5]
[6] 0.00 0 0 6 c [6]
----------------------------------------
@end example
The @code{self} field of the cycle's primary line is the total time
spent in all the functions of the cycle. It equals the sum of the
@code{self} fields for the individual functions in the cycle, found
in the entry in the subroutine lines for these functions.
The @code{children} fields of the cycle's primary line and subroutine lines
count only subroutines outside the cycle. Even though @code{a} calls
@code{b}, the time spent in those calls to @code{b} is not counted in
@code{a}'s @code{children} time. Thus, we do not encounter the problem of
what to do when the time in those calls to @code{b} includes indirect
recursive calls back to @code{a}.
The @code{children} field of a caller-line in the cycle's entry estimates
the amount of time spent @emph{in the whole cycle}, and its other
subroutines, on the times when that caller called a function in the cycle.
The @code{calls} field in the primary line for the cycle has two numbers:
first, the number of times functions in the cycle were called by functions
outside the cycle; second, the number of times they were called by
functions in the cycle (including times when a function in the cycle calls
itself). This is a generalization of the usual split into nonrecursive and
recursive calls.
The @code{calls} field of a subroutine-line for a cycle member in the
cycle's entry says how many time that function was called from functions in
the cycle. The total of all these is the second number in the primary line's
@code{calls} field.
In the individual entry for a function in a cycle, the other functions in
the same cycle can appear as subroutines and as callers. These lines show
how many times each function in the cycle called or was called from each other
function in the cycle. The @code{self} and @code{children} fields in these
lines are blank because of the difficulty of defining meanings for them
when recursion is going on.
@node Implementation, Sampling Error, Call Graph, Top
@chapter Implementation of Profiling
Profiling works by changing how every function in your program is compiled
so that when it is called, it will stash away some information about where
it was called from. From this, the profiler can figure out what function
called it, and can count how many times it was called. This change is made
by the compiler when your program is compiled with the @samp{-pg} option.
Profiling also involves watching your program as it runs, and keeping a
histogram of where the program counter happens to be every now and then.
Typically the program counter is looked at around 100 times per second of
run time, but the exact frequency may vary from system to system.
A special startup routine allocates memory for the histogram and sets up a
clock signal handler to make entries in it. Use of this special startup
routine is one of the effects of using @samp{cc -pg} to link. The startup
file also includes an @code{exit} function which is responsible for writing
the file @file{gmon.out}.
Number-of-calls information for library routines is collected by using a
special version of the C library. The programs in it are the same as in
the usual C library, but they were compiled with @samp{-pg}. If you link
your program with @samp{cc -pg}, it automatically uses the profiling
version of the library.
The output @code{gprof} gives no indication of parts of your program that
are limited by I/O or swapping bandwidth. This is because samples of the
program counter are taken at fixed intervals of run time. Therefore, the
time measurements in @code{gprof} output say nothing about time that your
program was not running. For example, a part of the program that creates
so much data that it cannot all fit in physical memory at once may run very
slowly due to thrashing, but @code{gprof} will say it uses little time. On
the other hand, sampling by run time has the advantage that the amount of
load due to other users won't directly affect the output you get.
@node Sampling Error, Assumptions, Implementation, Top
@chapter Statistical Inaccuracy of @code{gprof} Output
The run-time figures that @code{gprof} gives you are based on a sampling
process, so they are subject to statistical inaccuracy. If a function runs
only a small amount of time, so that on the average the sampling process
ought to catch that function in the act only once, there is a pretty good
chance it will actually find that function zero times, or twice.
By contrast, the number-of-calls figures are derived by counting, not
sampling. They are completely accurate and will not vary from run to run
if your program is deterministic.
The @dfn{sampling period} that is printed at the beginning of the flat
profile says how often samples are taken. The rule of thumb is that a
run-time figure is accurate if it is considerably bigger than the sampling
period.
The actual amount of error is usually more than one sampling period. In
fact, if a value is @var{n} times the sampling period, the @emph{expected}
error in it is the square-root of @var{n} sampling periods. If the
sampling period is 0.01 seconds and @code{foo}'s run-time is 1 second, the
expected error in @code{foo}'s run-time is 0.1 seconds. It is likely to
vary this much @emph{on the average} from one profiling run to the next.
(@emph{Sometimes} it will vary more.)
This does not mean that a small run-time figure is devoid of information.
If the program's @emph{total} run-time is large, a small run-time for one
function does tell you that that function used an insignificant fraction of
the whole program's time. Usually this means it is not worth optimizing.
One way to get more accuracy is to give your program more (but similar)
input data so it will take longer. Another way is to combine the data from
several runs, using the @samp{-s} option of @code{gprof}. Here is how:
@enumerate
@item
Run your program once.
@item
Issue the command @samp{mv gmon.out gmon.sum}.
@item
Run your program again, the same as before.
@item
Merge the new data in @file{gmon.out} into @file{gmon.sum} with this command:
@example
gprof -s @var{executable-file} gmon.out gmon.sum
@end example
@item
Repeat the last two steps as often as you wish.
@item
Analyze the cumulative data using this command:
@example
gprof @var{executable-file} gmon.sum > @var{output-file}
@end example
@end enumerate
@node Assumptions, Incompatibilities, Sampling Error, Top
@chapter Estimating @code{children} Times Uses an Assumption
Some of the figures in the call graph are estimates---for example, the
@code{children} time values and all the the time figures in caller and
subroutine lines.
There is no direct information about these measurements in the profile
data itself. Instead, @code{gprof} estimates them by making an assumption
about your program that might or might not be true.
The assumption made is that the average time spent in each call to any
function @code{foo} is not correlated with who called @code{foo}. If
@code{foo} used 5 seconds in all, and 2/5 of the calls to @code{foo} came
from @code{a}, then @code{foo} contributes 2 seconds to @code{a}'s
@code{children} time, by assumption.
This assumption is usually true enough, but for some programs it is far
from true. Suppose that @code{foo} returns very quickly when its argument
is zero; suppose that @code{a} always passes zero as an argument, while
other callers of @code{foo} pass other arguments. In this program, all the
time spent in @code{foo} is in the calls from callers other than @code{a}.
But @code{gprof} has no way of knowing this; it will blindly and
incorrectly charge 2 seconds of time in @code{foo} to the children of
@code{a}.
We hope some day to put more complete data into @file{gmon.out}, so that
this assumption is no longer needed, if we can figure out how. For the
nonce, the estimated figures are usually more useful than misleading.
@node Incompatibilities, , Assumptions, Top
@chapter Incompatibilities with Unix @code{gprof}
GNU @code{gprof} and Berkeley Unix @code{gprof} use the same data file
@file{gmon.out}, and provide essentially the same information. But there a
few differences.@refill
GNU @code{gprof} does not support the @samp{-c} option which prints a
static call graph based on reading the machine language of your
program. We think that program cross-references ought to be based on
the source files, which can be analyzed in a machine-independent
fashion.@refill
For a recursive function, Unix @code{gprof} lists the function as a parent
and as a child, with a @code{calls} field that lists the number of
recursive calls. GNU @code{gprof} omits these lines and puts the number of
recursive calls in the primary line.
When a function is suppressed from the call graph with @samp{-e}, GNU
@code{gprof} still lists it as a subroutine of functions that call it.
The function names printed in GNU @code{gprof} output do not include
the leading underscores that are added internally to the front of all
C identifiers on many operating systems.
The blurbs, field widths, and output formats are different. GNU
@code{gprof} prints blurbs after the tables, so that you can see the
tables without skipping the blurbs.
@contents
@bye

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,23 @@
#! /bin/sh
#
# Convert coff libc to a coff-encapsulated libc
# suitable for linking with the GNU linker.
#
# Extract all members of /lib/libc.a (using coff ar).
# Convert each using robotussin.
# Create new libc (using gnu ar) with members in the same order as coff libc.
# set -e makes this script exit if any command gets an error
set -e
mkdir tmp
cd tmp
/bin/ar x /lib/libc.a
for i in *.o
do
../robotussin $i x
mv x $i
done
rm -f ../libc.a
../ar rs ../libc.a `/bin/ar t /lib/libc.a`
cd ..

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,272 @@
/*
* objdump
*
* dump information about an object file. Until there is other documentation,
* refer to the manual page dump(1) in the system 5 program's reference manual
*/
#include <stdio.h>
#ifndef COFF_ENCAPSULATE
#include "a.out.gnu.h"
#else
#include "a.out.encap.h"
#endif
char *malloc();
int nsyms;
struct nlist *symtbl;
char *strtbl;
int strsize;
read_symbols (execp, f)
struct exec *execp;
FILE *f;
{
int i;
struct nlist *sp;
if (symtbl)
return;
nsyms = execp->a_syms / sizeof (struct nlist);
if (nsyms == 0)
return;
symtbl = (struct nlist *)malloc (nsyms * sizeof (struct nlist));
if (symtbl == NULL) {
fprintf (stderr, "can't malloc for %d symbols\n",
nsyms);
exit (1);
}
fseek (f, N_STROFF(*execp), 0);
if (fread ((char *)&strsize, sizeof strsize, 1, f) != 1) {
fprintf (stderr, "can't get string table size\n");
exit (1);
}
strtbl = malloc (strsize);
if (strtbl == NULL) {
fprintf (stderr, "can't malloc %d bytes for string table\n");
exit (1);
}
fseek (f, N_STROFF (*execp), 0);
if (fread (strtbl, 1, strsize, f) != strsize) {
fprintf (stderr, "error reading string table\n");
exit (1);
}
fseek (f, N_SYMOFF (*execp), 0);
if (fread ((char *)symtbl, sizeof (struct nlist), nsyms, f) != nsyms) {
fprintf (stderr, "error reading symbol table\n");
exit (1);
}
for (i = 0, sp = symtbl; i < nsyms; i++, sp++) {
if (sp->n_un.n_strx < 0 || sp->n_un.n_strx > strsize)
sp->n_un.n_name = "<bad string table index>";
else
sp->n_un.n_name = strtbl + sp->n_un.n_strx;
}
}
free_symbols ()
{
if (symtbl)
free (symtbl);
symtbl = NULL;
if (strtbl)
free (strtbl);
strtbl = NULL;
}
usage ()
{
fprintf (stderr, "usage: dump [-h] [-n] [-r] [-t] obj ...\n");
exit (1);
}
int hflag;
int nflag;
int rflag;
int tflag;
main (argc, argv)
char **argv;
{
int c;
extern char *optarg;
extern int optind;
int seenflag = 0;
while ((c = getopt (argc, argv, "hnrt")) != EOF) {
seenflag = 1;
switch (c) {
case 't': tflag = 1; break;
case 'r': rflag = 1; break;
case 'n': nflag = 1; break;
case 'h': hflag = 1; break;
default:
usage ();
}
}
if (seenflag == 0 || optind == argc)
usage ();
while (optind < argc)
doit (argv[optind++]);
}
doit (name)
char *name;
{
FILE *f;
struct exec exec;
printf ("%s:\n", name);
f = fopen (name, "r");
if (f == NULL) {
fprintf (stderr, "can't open %s\n", name);
return;
}
#ifdef HEADER_SEEK
HEADER_SEEK (f);
#endif
if (fread ((char *)&exec, sizeof exec, 1, f) != 1) {
fprintf (stderr, "can't read header for %s\n", name);
return;
}
if (N_BADMAG (exec)) {
fprintf (stderr, "%s is not an object file\n", name);
return;
}
if (hflag)
dump_header (&exec);
if (nflag)
dump_nstuff (&exec);
if (tflag)
dump_sym (&exec, f);
if (rflag)
dump_reloc (&exec, f);
free_symbols ();
}
dump_header (execp)
struct exec *execp;
{
int x;
printf ("magic: 0x%x (%o) ", execp->a_magic, execp->a_magic & 0xffff);
#ifdef COFF_ENCAPSULATE
printf ("machtype: %d ", execp->a_machtype);
printf ("flags: 0x%x ", execp->a_flags);
#endif
printf ("text 0x%x ", execp->a_text);
printf ("data 0x%x ", execp->a_data);
printf ("bss 0x%x\n", execp->a_bss);
printf ("nsyms %d", execp->a_syms / sizeof (struct nlist));
x = execp->a_syms % sizeof (struct nlist);
if (x)
printf (" (+ %d bytes)", x);
printf (" entry 0x%x ", execp->a_entry);
printf ("trsize 0x%x ", execp->a_trsize);
printf ("drsize 0x%x\n", execp->a_drsize);
}
dump_nstuff (execp)
struct exec *execp;
{
printf ("N_BADMAG %d\n", N_BADMAG (*execp));
printf ("N_TXTOFF 0x%x\n", N_TXTOFF (*execp));
printf ("N_SYMOFF 0x%x\n", N_SYMOFF (*execp));
printf ("N_STROFF 0x%x\n", N_STROFF (*execp));
printf ("N_TXTADDR 0x%x\n", N_TXTADDR (*execp));
printf ("N_DATADDR 0x%x\n", N_DATADDR (*execp));
}
dump_sym (execp, f)
struct exec *execp;
FILE *f;
{
int i;
struct nlist *sp;
read_symbols (execp, f);
if (nsyms == 0) {
printf ("no symbols\n");
return;
}
printf ("%3s: %4s %5s %4s %8s\n",
"#", "type", "other", "desc", "val");
for (i = 0, sp = symtbl; i < nsyms; i++, sp++) {
printf ("%3d: %4x %5x %4x %8x %s\n",
i, sp->n_type, sp->n_other, sp->n_desc, sp->n_value,
sp->n_un.n_name);
}
}
dump_reloc (execp, f)
struct exec *execp;
FILE *f;
{
read_symbols (execp, f);
if (execp->a_trsize) {
printf ("text reloc\n");
dump_reloc1 (execp, f, N_TRELOFF (*execp), execp->a_trsize);
}
if (execp->a_drsize) {
printf ("data reloc\n");
dump_reloc1 (execp, f, N_DRELOFF (*execp), execp->a_drsize);
}
}
dump_reloc1 (execp, f, off, size)
struct exec *execp;
FILE *f;
{
int nreloc;
struct relocation_info reloc;
int i;
nreloc = size / sizeof (struct relocation_info);
printf ("%3s: %3s %8s %4s\n", "#", "len", "adr", "sym");
fseek (f, off, 0);
for (i = 0; i < nreloc; i++) {
if (fread ((char *)&reloc, sizeof reloc, 1, f) != 1) {
fprintf (stderr, "error reading reloc\n");
return;
}
printf ("%3d: %3d %8x ", i, 1 << reloc.r_length,
reloc.r_address);
if (reloc.r_extern) {
printf ("%4d ", reloc.r_symbolnum);
if (reloc.r_symbolnum < nsyms)
printf ("%s ",
symtbl[reloc.r_symbolnum].n_un.n_name);
} else {
printf (" ");
switch (reloc.r_symbolnum & ~N_EXT) {
case N_TEXT: printf (".text "); break;
case N_DATA: printf (".data "); break;
case N_BSS: printf (".bss "); break;
case N_ABS: printf (".abs "); break;
default: printf ("base %x ", reloc.r_symbolnum); break;
}
}
if (reloc.r_pcrel) printf ("PCREL ");
#if 0
if (reloc.r_pad) printf ("PAD %x ", reloc.r_pad);
#endif
printf ("\n");
}
}

View File

@@ -0,0 +1,26 @@
/* Dummy ranlib program for GNU. All it does is
`ar rs LIBRARY' for each library specified. */
/* The makefile generates a -D switch to define AR_PROG
as the location of the GNU AR program. */
char *prog = AR_PROG;
main (argc, argv)
int argc;
char **argv;
{
int i;
for (i = 1; i < argc; i++)
{
int pid = fork ();
if (pid == 0)
{
execl (prog, prog, "rs", argv[i], 0);
perror (prog);
exit (1);
}
wait (0);
}
exit (0);
}

View File

@@ -0,0 +1,17 @@
/* ranlib.h 4.1 83/05/03 */
/*
* Structure of the __.SYMDEF table of contents for an archive.
* __.SYMDEF begins with a word giving the number of ranlib structures
* which immediately follow, and then continues with a string
* table consisting of a word giving the number of bytes of strings
* which follow and then the strings themselves.
* The ran_strx fields index the string table whose first byte is numbered 0.
*/
struct ranlib {
union {
off_t ran_strx; /* string table index of */
char *ran_name; /* symbol defined by */
} ran_un;
off_t ran_off; /* library member at this offset */
};

View File

@@ -0,0 +1,610 @@
/* Convert COFF-format object file to BSD format.
Used for converting the system libraries so GNU ld can link them.
Copyright (C) 1988 Free Software Foundation, Inc.
NO WARRANTY
BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT
WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,
RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS"
WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY
AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
CORRECTION.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY
WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE
LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR
OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR
DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR
A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS
PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
GENERAL PUBLIC LICENSE TO COPY
1. You may copy and distribute verbatim copies of this source file
as you receive it, in any medium, provided that you conspicuously
and appropriately publish on each copy a valid copyright notice
"Copyright (C) 1988 Free Software Foundation, Inc.", and include
following the copyright notice a verbatim copy of the above disclaimer
of warranty and of this License.
2. You may modify your copy or copies of this source file or
any portion of it, and copy and distribute such modifications under
the terms of Paragraph 1 above, provided that you also do the following:
a) cause the modified files to carry prominent notices stating
that you changed the files and the date of any change; and
b) cause the whole of any work that you distribute or publish,
that in whole or in part contains or is a derivative of this
program or any part thereof, to be licensed at no charge to all
third parties on terms identical to those contained in this
License Agreement (except that you may choose to grant more extensive
warranty protection to some or all third parties, at your option).
c) You may charge a distribution fee for the physical act of
transferring a copy, and you may at your option offer warranty
protection in exchange for a fee.
Mere aggregation of another unrelated program with this program (or its
derivative) on a volume of a storage or distribution medium does not bring
the other program under the scope of these terms.
3. You may copy and distribute this program (or a portion or derivative
of it, under Paragraph 2) in object code or executable form under the terms
of Paragraphs 1 and 2 above provided that you also do one of the following:
a) accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of
Paragraphs 1 and 2 above; or,
b) accompany it with a written offer, valid for at least three
years, to give any third party free (except for a nominal
shipping charge) a complete machine-readable copy of the
corresponding source code, to be distributed under the terms of
Paragraphs 1 and 2 above; or,
c) accompany it with the information you received as to where the
corresponding source code may be obtained. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form alone.)
For an executable file, complete source code means all the source code for
all modules it contains; but, as a special exception, it need not include
source code for modules which are standard libraries that accompany the
operating system on which the executable file runs.
4. You may not copy, sublicense, distribute or transfer this program
except as expressly provided under this License Agreement. Any attempt
otherwise to copy, sublicense, distribute or transfer this program is void and
your rights to use the program under this License agreement shall be
automatically terminated. However, parties who have received computer
software programs from you with this License Agreement will not have
their licenses terminated so long as such parties remain in full compliance.
5. If you wish to incorporate parts of this program into other free
programs whose distribution conditions are different, write to the Free
Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not yet
worked out a simple rule that can be stated here, but we will often permit
this. We will be guided by the two goals of preserving the free status of
all derivatives of our free software and of promoting the sharing and reuse of
software.
In other words, you are welcome to use, share and improve this program.
You are forbidden to forbid anyone else to use, share and improve
what you give them. Help stamp out software-hoarding! */
/*
** Robotussin - convert COFF format object files to BSD format.
**
** written by Jeff Lewis, donated to the Free Software Foundation.
**
** BUGS:
** Should do more to verify that the input COFF file meets our
** expectations.
** On machines where the structure of the COFF data in the file does not
** match the structure of the COFF data declared (when, for example
** sizeof (struct filhdr) != FILHSZ), this program will fail. (Don't
** ask me why this is ever allowed to come about). Accessor functions/
** macros that painstakingly extract the data out of the file and stuff
** it in the memory struct should be written to fix this on such machines.
**
** CAVEATS:
** This program cannot claim correctness, however, it does appear
** to work on my fairly vanilla Sys5r2 machine. Someone with the time
** and a fine tooth comb (not to mention some documentation on COFF)
** should correct this!
*/
#ifndef COFF_ENCAPSULATE
#define COFF_ENCAPSULATE
#endif
/* Customization for a particular machine. */
#define INPUT_MAGIC I386MAGIC
#define nounderscore
#include <stdio.h>
#include <varargs.h>
#include <fcntl.h>
#include "a.out.encap.h"
#define N_ABSOLUTE N_ABS /* N_ABS will be redefined in syms.h */
#undef N_ABS
#include <filehdr.h>
#include <aouthdr.h>
#include <scnhdr.h>
#include <syms.h>
#include <reloc.h>
/* Because of struct alignment on dwords sizeof (struct syment) is different
than the syments stored in the file. Therefore, we must kludge: */
#define sizeof_syment (SYMESZ)
#define sizeof_reloc (RELSZ)
#define sizeof_section (SCNHSZ)
#define sizeof_coff_header (FILHSZ)
extern long lseek ();
extern void exit ();
extern char *memcpy ();
extern int errno;
void error (), sys_error ();
static void reloc_segment ();
char *mem_alloc ();
int fd_in, fd_out; /* input and output file descriptors */
struct filehdr coff_header; /* file header from the input file */
struct exec bsd_header; /* file header for the output file */
struct syment *coff_sym_listp; /* list of symbols from the input */
int *symbol_map; /* mapping of input symbol #'s to
output symbol numbers */
char *text_and_data; /* space for text & data section data */
char *relocations; /* space for output reloc entries */
int verbose_flag; /* flag for debugging */
struct scnhdr coff_text_header; /* COFF text section header */
struct scnhdr coff_data_header; /* COFF data section header */
struct scnhdr coff_bss_header; /* COFF bss section header */
int text_sect_num; /* COFF section # for text */
int data_sect_num; /* COFF section # for data */
int bss_sect_num; /* COFF section # for bss */
int
main (argc, argv)
int argc;
char **argv;
{
int i, j;
char *coff_string_table, *bsd_string_table;
register char *pc, *pc2;
int string_table_len;
int symbol_count;
struct scnhdr section;
struct nlist name;
if (argc < 3)
error ("usage: %s cofffile bsdfile", argv[0]);
if (argc > 3)
verbose_flag = 1;
fd_in = open (argv[1], O_RDONLY);
if (fd_in < 0)
sys_error ("can't open %s", argv[1]);
fd_out = open (argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd_out < 0)
sys_error ("can't open %s", argv[2]);
/*
** Read in the file header and all section headers searching
** for text, data and bss. We note the section #'s of these
** sections for use when examining symbols.
*/
if (read (fd_in, &coff_header, sizeof_coff_header) != sizeof_coff_header)
error ("can't read file header");
if (coff_header.f_magic != INPUT_MAGIC)
error ("bad magic number in coff file\n");
lseek (fd_in, sizeof_coff_header + coff_header.f_opthdr, 0);
for (i = 1; i <= coff_header.f_nscns; ++i)
{
if (read (fd_in, &section, sizeof_section) != sizeof_section)
error ("can't read section header #%d", i);
if (strcmp (section.s_name, _TEXT) == 0)
{
text_sect_num = i;
memcpy (&coff_text_header, &section, sizeof section);
}
else if (strcmp (section.s_name, _DATA) == 0)
{
data_sect_num = i;
memcpy (&coff_data_header, &section, sizeof section);
}
else if (strcmp (section.s_name, _BSS) == 0)
{
bss_sect_num = i;
memcpy (&coff_bss_header, &section, sizeof section);
}
}
/*
** Pass1 thru the symbol table - count usable symbols and map
** old symbol #'s into new ones (as used by relocation
** info). We're only interested in keeping the kinds of symbols
** we'd expect to find in a BSD library object file: no debug
** symbols, file names, section definition symbols, etc.
** Section definition symbols are referenced by reloc entries
** in the COFF file, so we note their position with a negative
** symbol number indicating the section. -1 is used to flag
** symbols we're not interested in, yielding an unexpected error
** if we find any reloc entries referencing them.
*/
coff_sym_listp =
(struct syment *) mem_alloc (coff_header.f_nsyms * sizeof (struct syment));
symbol_map = (int *) mem_alloc (coff_header.f_nsyms * sizeof *symbol_map);
if (lseek (fd_in, coff_header.f_symptr, 0) < 0L)
sys_error ("can't seek to COFF symbols");
for (i = 0; i < coff_header.f_nsyms; ++i)
{
if (read (fd_in, coff_sym_listp + i, sizeof_syment) != sizeof_syment)
error ("can't read COFF symbols");
}
symbol_count = 0;
for (i = 0; i < coff_header.f_nsyms; ++i)
{
if (coff_sym_listp[i].n_scnum != N_DEBUG
&& coff_sym_listp[i].n_name[0] != '.')
{
if (verbose_flag)
printf ("map %d to %d\n", i, symbol_count);
symbol_map[i] = symbol_count++;
}
else
{
if (coff_sym_listp[i].n_sclass == C_STAT)
{
if (strcmp (coff_sym_listp[i].n_name, _TEXT) == 0)
symbol_map[i] = -N_TEXT;
else if (strcmp (coff_sym_listp[i].n_name, _DATA) == 0)
symbol_map[i] = -N_DATA;
else if (strcmp (coff_sym_listp[i].n_name, _BSS) == 0)
symbol_map[i] = -N_BSS;
else
symbol_map[i] = -1;
}
else
{
symbol_map[i] = -1;
}
}
/* skip auxillary entries */
j = coff_sym_listp[i].n_numaux;
if (j != 0)
{
if (j < 0)
error ("invalid numaux");
if (j != 1)
fprintf (stderr, "unlikely numaux value\n");
while (--j >= 0)
++i;
}
}
/* now we know enough to write the output file header */
bsd_header.a_magic = OMAGIC;
bsd_header.a_text = coff_text_header.s_size;
bsd_header.a_data = coff_data_header.s_size;
bsd_header.a_bss = coff_bss_header.s_size;
bsd_header.a_syms = symbol_count * sizeof (struct nlist);
bsd_header.a_entry = 0;
bsd_header.a_trsize = coff_text_header.s_nreloc * sizeof (struct relocation_info);
bsd_header.a_drsize = coff_data_header.s_nreloc * sizeof (struct relocation_info);
if (write (fd_out, &bsd_header, sizeof bsd_header) != sizeof bsd_header)
sys_error ("can't write BSD header");
/*
** Read in and save text and data sections - some data in
** these sections may need to be altered due to relocations.
*/
text_and_data = (char *) mem_alloc (coff_text_header.s_size + coff_data_header.s_size);
if (lseek (fd_in, coff_text_header.s_scnptr, 0) < 0L)
sys_error ("can't seek to text section");
if (read (fd_in, text_and_data, coff_text_header.s_size) != coff_text_header.s_size)
error ("can't read text section");
if (lseek (fd_in, coff_data_header.s_scnptr, 0) < 0L)
sys_error ("can't seek to data section");
if (read (fd_in, text_and_data + coff_text_header.s_size, coff_data_header.s_size) != coff_data_header.s_size)
error ("can't read data section");
/*
** Convert the relocation entries and do any text or data
** modifications necessary.
*/
relocations = (char *) mem_alloc (bsd_header.a_trsize + bsd_header.a_drsize);
reloc_segment (&coff_text_header, relocations);
reloc_segment (&coff_data_header, relocations + bsd_header.a_trsize);
if (write (fd_out, text_and_data, coff_text_header.s_size + coff_data_header.s_size)
!= coff_text_header.s_size + coff_data_header.s_size)
sys_error ("can't write text and data sections");
/* ZZ - are there any alignment considerations?? */
if ((coff_text_header.s_size & 1) || (coff_data_header.s_size & 1))
fprintf (stderr, "non-aligned text or data section\n");
if (write (fd_out, relocations, bsd_header.a_trsize + bsd_header.a_drsize)
!= bsd_header.a_trsize + bsd_header.a_drsize)
sys_error ("can't write relocation entries");
/*
** Second pass thru the symbol table.
** a COFF symbol entry may contain up to 8 chars of symbol name
** in the entry itself - symbol names > 8 go into the string table,
** whereas the BSD entry puts all symbol names into the string
** table.
*/
if (lseek (fd_in, coff_header.f_symptr + coff_header.f_nsyms * sizeof_syment, 0) < 0L)
error ("can't seek to string table");
i = read (fd_in, &string_table_len, sizeof string_table_len);
if (i == sizeof string_table_len)
{
coff_string_table = mem_alloc (string_table_len);
string_table_len -= sizeof string_table_len;
i = read (fd_in, coff_string_table + sizeof string_table_len, string_table_len);
if (i < 0)
error ("can't read string table");
if (i != string_table_len)
error ("truncated string table - expected %d, got %d",
string_table_len, i);
}
else
{
string_table_len = 0;
}
bsd_string_table = mem_alloc (string_table_len + coff_header.f_nsyms * (SYMNMLEN + 1));
pc = bsd_string_table + sizeof string_table_len;
for (i = 0; i < coff_header.f_nsyms; ++i)
{
if (coff_sym_listp[i].n_scnum != N_DEBUG
&& coff_sym_listp[i].n_name[0] != '.')
{
if (coff_sym_listp[i].n_zeroes == 0)
{
j = pc - bsd_string_table;
#ifndef nounderscore
if (coff_sym_listp[i].n_sclass == C_EXT
|| coff_sym_listp[i].n_sclass == C_STAT)
*pc++ = '_';
#endif
pc2 = coff_string_table + coff_sym_listp[i].n_offset;
while (*pc++ = *pc2++)
/* null */ ;
name.n_un.n_strx = j;
}
else
{
pc2 = &coff_sym_listp[i].n_name[0];
j = pc - bsd_string_table;
#ifndef nounderscore
if (coff_sym_listp[i].n_sclass == C_EXT
|| coff_sym_listp[i].n_sclass == C_STAT)
*pc++ = '_';
#endif
{
int x;
for (x = 0; x < SYMNMLEN; x++)
{
if (*pc2 == 0)
break;
*pc++ = *pc2++;
}
*pc++ = 0;
}
name.n_un.n_strx = j;
}
switch (coff_sym_listp[i].n_scnum)
{
case N_ABS:
name.n_type = N_ABSOLUTE;
break;
case N_UNDEF:
name.n_type = N_UNDF;
break;
default:
if (coff_sym_listp[i].n_scnum == text_sect_num)
name.n_type = N_TEXT;
else if (coff_sym_listp[i].n_scnum == data_sect_num)
name.n_type = N_DATA;
else if (coff_sym_listp[i].n_scnum == bss_sect_num)
name.n_type = N_BSS;
break;
}
if (coff_sym_listp[i].n_sclass == C_EXT)
name.n_type |= N_EXT;
name.n_other = 0;
name.n_desc = 0;
name.n_value = coff_sym_listp[i].n_value;
if (write (fd_out, &name, sizeof name) != sizeof name)
sys_error ("can't write symbol");
}
/* skip auxillary entries */
j = coff_sym_listp[i].n_numaux;
if (j != 0)
{
while (--j >= 0)
++i;
}
}
i = *((int *) bsd_string_table) = pc - bsd_string_table;
if (write (fd_out, bsd_string_table, i) != i)
error ("can't write string table");
close (fd_in);
close (fd_out);
exit (0);
}
/*
** Convert the relocation entries and do any text or data
** modifications necessary.
*/
static void
reloc_segment (section_headerp, reloc_infop)
struct scnhdr *section_headerp;
struct relocation_info *reloc_infop;
{
struct reloc coff_reloc;
int i;
if (lseek (fd_in, section_headerp->s_relptr, 0) < 0L)
error ("can't seek to relocation entries");
for (i = 0; i < section_headerp->s_nreloc; ++i)
{
if (read (fd_in, &coff_reloc, sizeof_reloc) != sizeof_reloc)
error ("can't read relocation entry");
if (verbose_flag)
printf ("vaddr = 0x%x, symndx = %d\n", coff_reloc.r_vaddr, coff_reloc.r_symndx);
/*
** The reloc references a symbol declared common, thus the
** value of the symbol holds its size (in bytes). In COFF,
** apparently this info is also put into the binary -
** BSD doesn't like this, so we subtract it out.
*/
if (coff_sym_listp[coff_reloc.r_symndx].n_scnum == N_UNDEF)
{
if (coff_sym_listp[coff_reloc.r_symndx].n_value != 0)
{
if (verbose_flag)
printf ("adjust common 0x%x (%d)\n",
coff_sym_listp[coff_reloc.r_symndx].n_value,
coff_sym_listp[coff_reloc.r_symndx].n_value);
switch (coff_reloc.r_type)
{
case R_RELBYTE:
*((char *) (text_and_data + coff_reloc.r_vaddr))
-= coff_sym_listp[coff_reloc.r_symndx].n_value;
break;
case R_RELWORD:
*((short *) (text_and_data + coff_reloc.r_vaddr))
-= coff_sym_listp[coff_reloc.r_symndx].n_value;
break;
case R_RELLONG:
case R_DIR32: /* these are the only two that really show up */
case R_PCRLONG:
*((int *) (text_and_data + coff_reloc.r_vaddr))
-= coff_sym_listp[coff_reloc.r_symndx].n_value;
break;
default:
error ("unknown relocation type 0%o", coff_reloc.r_type);
}
}
}
/*
** >= 0 means its an extern - value is the output symbol #.
** < 0 means its an intern - value is N_TEXT, N_DATA or N_BSS.
*/
if (symbol_map[coff_reloc.r_symndx] >= 0)
{
reloc_infop->r_symbolnum = symbol_map[coff_reloc.r_symndx];
reloc_infop->r_extern = 1;
}
else
{
if (symbol_map[coff_reloc.r_symndx] == -1)
error ("Oops! possible bug - reloc reference to ignored symbol");
reloc_infop->r_symbolnum = -symbol_map[coff_reloc.r_symndx];
reloc_infop->r_extern = 0;
}
/*
** COFF address includes the section address - BSD doesn't, so
** subtract it out.
*/
reloc_infop->r_address = coff_reloc.r_vaddr - section_headerp->s_vaddr;
switch (coff_reloc.r_type)
{
case R_PCRLONG:
reloc_infop->r_pcrel = 1;
reloc_infop->r_length = 2; /* 4 bytes */
break;
case R_DIR32:
reloc_infop->r_pcrel = 0;
reloc_infop->r_length = 2;
break;
default:
error ("can't handle coff reloction type 0%o", coff_reloc.r_type);
}
if (verbose_flag)
printf ("reloc: addr = 0x%x, synum = %d\n",
reloc_infop->r_address, reloc_infop->r_symbolnum);
reloc_infop->r_pad = 0;
++reloc_infop;
}
}
void
error (format, va_alist)
char *format;
va_dcl
{
va_list args;
va_start (args);
fprintf (stderr, "robotussin: ");
vfprintf (stderr, format, args);
putc ('\n', stderr);
va_end (args);
exit (1);
}
extern char *sys_errlist[];
extern int errno;
void
sys_error (format, va_alist)
char *format;
va_dcl
{
va_list args;
va_start (args);
fprintf (stderr, "robotussin: ");
vfprintf (stderr, format, args);
fprintf (stderr, ": %s\n", sys_errlist[errno]);
va_end (args);
exit (1);
}
extern char *malloc ();
char *
mem_alloc (size)
int size;
{
char *pc;
if ((pc = malloc (size)) == NULL)
error ("memory exhausted!");
return pc;
}
/* end */

View File

@@ -0,0 +1,428 @@
/* Size of rel file utility (`size') for GNU.
Copyright (C) 1986 Free Software Foundation, Inc.
NO WARRANTY
BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT
WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,
RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS"
WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY
AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
CORRECTION.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY
WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE
LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR
OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR
DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR
A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS
PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
GENERAL PUBLIC LICENSE TO COPY
1. You may copy and distribute verbatim copies of this source file
as you receive it, in any medium, provided that you conspicuously
and appropriately publish on each copy a valid copyright notice
"Copyright (C) 1986 Free Software Foundation, Inc.", and include
following the copyright notice a verbatim copy of the above disclaimer
of warranty and of this License.
2. You may modify your copy or copies of this source file or
any portion of it, and copy and distribute such modifications under
the terms of Paragraph 1 above, provided that you also do the following:
a) cause the modified files to carry prominent notices stating
that you changed the files and the date of any change; and
b) cause the whole of any work that you distribute or publish,
that in whole or in part contains or is a derivative of this
program or any part thereof, to be licensed at no charge to all
third parties on terms identical to those contained in this
License Agreement (except that you may choose to grant more extensive
warranty protection to some or all third parties, at your option).
c) You may charge a distribution fee for the physical act of
transferring a copy, and you may at your option offer warranty
protection in exchange for a fee.
Mere aggregation of another unrelated program with this program (or its
derivative) on a volume of a storage or distribution medium does not bring
the other program under the scope of these terms.
3. You may copy and distribute this program (or a portion or derivative
of it, under Paragraph 2) in object code or executable form under the terms
of Paragraphs 1 and 2 above provided that you also do one of the following:
a) accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of
Paragraphs 1 and 2 above; or,
b) accompany it with a written offer, valid for at least three
years, to give any third party free (except for a nominal
shipping charge) a complete machine-readable copy of the
corresponding source code, to be distributed under the terms of
Paragraphs 1 and 2 above; or,
c) accompany it with the information you received as to where the
corresponding source code may be obtained. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form alone.)
For an executable file, complete source code means all the source code for
all modules it contains; but, as a special exception, it need not include
source code for modules which are standard libraries that accompany the
operating system on which the executable file runs.
4. You may not copy, sublicense, distribute or transfer this program
except as expressly provided under this License Agreement. Any attempt
otherwise to copy, sublicense, distribute or transfer this program is void and
your rights to use the program under this License agreement shall be
automatically terminated. However, parties who have received computer
software programs from you with this License Agreement will not have
their licenses terminated so long as such parties remain in full compliance.
5. If you wish to incorporate parts of this program into other free
programs whose distribution conditions are different, write to the Free
Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not yet
worked out a simple rule that can be stated here, but we will often permit
this. We will be guided by the two goals of preserving the free status of
all derivatives of our free software and of promoting the sharing and reuse of
software.
In other words, you are welcome to use, share and improve this program.
You are forbidden to forbid anyone else to use, share and improve
what you give them. Help stamp out software-hoarding! */
#include <stdio.h>
#include <ar.h>
#include <sys/types.h>
#include <sys/file.h>
#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
#ifdef USG
#include <fcntl.h>
#include <string.h>
#else
#include <strings.h>
#endif
/* Struct or union for header of object file. */
#define HEADER_TYPE struct exec
/* Number of input file names 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;
/* Offset within archive of the current member,
if we are processing an archive. */
int member_offset;
void do_one_file (), do_one_rel_file ();
char *concat ();
main (argc, argv)
char **argv;
int argc;
{
int i;
number_of_files = argc - 1;
printf ("text\tdata\tbss\tdec\thex\n");
/* Now scan and describe the files. */
if (number_of_files == 0)
do_one_file ("a.out");
else
for (i = 1; i < argc; i++)
do_one_file (argv[i]);
}
/* Print the filename of the current file on 'outfile' (a stdio stream). */
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 len, magicnum, desc;
desc = open (name, O_RDONLY, 0);
if (desc < 0)
{
perror_name (name);
return;
}
input_name = name;
input_member = 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, &magicnum, sizeof magicnum);
if (len != sizeof magicnum)
error_with_file ("failure reading header");
else if (!N_BADMAG (*((struct exec *)&magicnum)))
do_one_rel_file (desc, 0);
else
{
char armag[SARMAG];
lseek (desc, 0, 0);
if (SARMAG != read (desc, armag, SARMAG) || strncmp (armag, ARMAG, SARMAG))
error_with_file ("malformed input file (not rel or archive)");
else
scan_library (desc);
}
close (desc);
}
/* Read in the archive data about one member.
subfile_offset is the address within the archive of the start of that data.
The value returned is the length of the member's contents, which does
not include the archive data about the member.
If there are no more valid members, zero is returned. */
int
decode_library_subfile (desc, subfile_offset)
int desc;
int subfile_offset;
{
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");
else
{
for (namelen = 0;
hdr1.ar_name[namelen] != 0
&& hdr1.ar_name[namelen] != ' '
&& hdr1.ar_name[namelen] != '/';
namelen++)
;
name = (char *) xmalloc (namelen+1);
strncpy (name, hdr1.ar_name, namelen);
*(name + namelen) = 0;
input_member = 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;
while (member_length = decode_library_subfile (desc, this_subfile_offset))
{
/* 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));
this_subfile_offset += ((member_length + sizeof (struct ar_hdr)) + 1) & -2;
}
}
void read_header ();
void
do_one_rel_file (desc, offset)
int desc;
int offset;
{
HEADER_TYPE header; /* file header read in here */
int total;
header.a_magic = 0;
read_header (desc, &header, offset);
if (N_BADMAG (header))
{
error_with_file ("bad magic number");
return;
}
{
int tsize, dsize, bsize;
tsize = header.a_text;
dsize = header.a_data;
bsize = header.a_bss;
total = tsize + dsize + bsize;
printf ("%d\t%d\t%d\t%d\t%x", tsize, dsize, bsize, total, total);
}
if (number_of_files > 1 || input_member)
{
printf ("\t");
print_file_name (stdout);
}
printf ("\n");
}
/* read a file's header */
void
read_header (desc, loc, offset)
int desc;
HEADER_TYPE *loc;
int offset;
{
int len;
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, loc, sizeof (struct exec));
if (len != sizeof (struct exec))
error_with_file ("failure reading header");
}
/* Report a fatal error.
STRING is a printf format string and ARG is one arg for it. */
fatal (string, arg)
char *string, *arg;
{
fprintf (stderr, "size: ");
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. */
error (string, arg)
char *string, *arg;
{
fprintf (stderr, "size: ");
fprintf (stderr, string, arg);
fprintf (stderr, "\n");
}
/* Report a nonfatal error.
STRING is printed, followed by the current file name. */
error_with_file (string)
char *string;
{
fprintf (stderr, "size: ");
print_file_name (stderr);
fprintf (stderr, ": ");
fprintf (stderr, string);
fprintf (stderr, "\n");
}
/* Report an error using the message for the last failed system call,
followed by the string NAME. */
perror_name (name)
char *name;
{
extern int errno, sys_nerr;
extern char *sys_errlist[];
char *s;
if (errno < sys_nerr)
s = concat (name, ": ", sys_errlist[errno]);
else
s = concat (name, ": ", "unknown error");
error (s, name);
}
/* Like malloc but get fatal error if memory is exhausted. */
int
xmalloc (size)
int size;
{
int result = malloc (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;
}

View File

@@ -0,0 +1,201 @@
/* Table of DBX symbol codes for the GNU system.
Copyright (C) 1988 Free Software Foundation, Inc.
NO WARRANTY
BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT
WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,
RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS"
WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY
AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
CORRECTION.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY
WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE
LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR
OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR
DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR
A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS
PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
GENERAL PUBLIC LICENSE TO COPY
1. You may copy and distribute verbatim copies of this source file
as you receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy a valid copyright notice "Copyright
(C) 1988 Free Software Foundation, Inc."; and include following the
copyright notice a verbatim copy of the above disclaimer of warranty
and of this License. You may charge a distribution fee for the
physical act of transferring a copy.
2. You may modify your copy or copies of this source file or
any portion of it, and copy and distribute such modifications under
the terms of Paragraph 1 above, provided that you also do the following:
a) cause the modified files to carry prominent notices stating
that you changed the files and the date of any change; and
b) cause the whole of any work that you distribute or publish,
that in whole or in part contains or is a derivative of this
program or any part thereof, to be licensed at no charge to all
third parties on terms identical to those contained in this
License Agreement (except that you may choose to grant more extensive
warranty protection to some or all third parties, at your option).
c) You may charge a distribution fee for the physical act of
transferring a copy, and you may at your option offer warranty
protection in exchange for a fee.
Mere aggregation of another unrelated program with this program (or its
derivative) on a volume of a storage or distribution medium does not bring
the other program under the scope of these terms.
3. You may copy and distribute this program or any portion of it in
compiled, executable or object code form under the terms of Paragraphs
1 and 2 above provided that you do the following:
a) accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of
Paragraphs 1 and 2 above; or,
b) accompany it with a written offer, valid for at least three
years, to give any third party free (except for a nominal
shipping charge) a complete machine-readable copy of the
corresponding source code, to be distributed under the terms of
Paragraphs 1 and 2 above; or,
c) accompany it with the information you received as to where the
corresponding source code may be obtained. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form alone.)
For an executable file, complete source code means all the source code for
all modules it contains; but, as a special exception, it need not include
source code for modules which are standard libraries that accompany the
operating system on which the executable file runs.
4. You may not copy, sublicense, distribute or transfer this program
except as expressly provided under this License Agreement. Any attempt
otherwise to copy, sublicense, distribute or transfer this program is void and
your rights to use the program under this License agreement shall be
automatically terminated. However, parties who have received computer
software programs from you with this License Agreement will not have
their licenses terminated so long as such parties remain in full compliance.
5. If you wish to incorporate parts of this program into other free
programs whose distribution conditions are different, write to the Free
Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not yet
worked out a simple rule that can be stated here, but we will often permit
this. We will be guided by the two goals of preserving the free status of
all derivatives our free software and of promoting the sharing and reuse of
software.
In other words, you are welcome to use, share and improve this program.
You are forbidden to forbid anyone else to use, share and improve
what you give them. Help stamp out software-hoarding! */
/* Global variable. Only the name is significant.
To find the address, look in the corresponding external symbol. */
__define_stab (N_GSYM, 0x20, "GSYM")
/* Function name for BSD Fortran. Only the name is significant.
To find the address, look in the corresponding external symbol. */
__define_stab (N_FNAME, 0x22, "FNAME")
/* Function name or text-segment variable for C. Value is its address.
Desc is supposedly starting line number, but GCC doesn't set it
and DBX seems not to miss it. */
__define_stab (N_FUN, 0x24, "FUN")
/* Data-segment variable with internal linkage. Value is its address. */
__define_stab (N_STSYM, 0x26, "STSYM")
/* BSS-segment variable with internal linkage. Value is its address. */
__define_stab (N_LCSYM, 0x28, "LCSYM")
/* Name of main routine. Only the name is significant.
This is not used in C. */
__define_stab (N_MAIN, 0x2a, "MAIN")
/* Register variable. Value is number of register. */
__define_stab (N_RSYM, 0x40, "RSYM")
/* Structure or union element. Value is offset in the structure. */
__define_stab (N_SSYM, 0x60, "SSYM")
/* Parameter variable. Value is offset from argument pointer.
(On most machines the argument pointer is the same as the frame pointer. */
__define_stab (N_PSYM, 0xa0, "PSYM")
/* Automatic variable in the stack. Value is offset from frame pointer. */
__define_stab (N_LSYM, 0x80, "LSYM")
/* Alternate entry point. Value is its address. */
__define_stab (N_ENTRY, 0xa4, "ENTRY")
/* Name of main source file.
Value is starting text address of the compilation. */
__define_stab (N_SO, 0x64, "SO")
/* Name of sub-source file.
Value is starting text address of the compilation. */
__define_stab (N_SOL, 0x84, "SOL")
/* Line number in text segment. Desc is the line number;
value is corresponding address. */
__define_stab (N_SLINE, 0x44, "SLINE")
/* Similar, for data segment. */
__define_stab (N_DSLINE, 0x46, "DSLINE")
/* Similar, for bss segment. */
__define_stab (N_BSLINE, 0x48, "BSLINE")
/* Beginning of an include file. Only Sun uses this.
In an object file, only the name is significant.
The Sun linker puts data into some of the other fields. */
__define_stab (N_BINCL, 0x82, "BINCL")
/* End of an include file. No name.
These two act as brackets around the file's output.
In an object file, there is no significant data in this entry.
The Sun linker puts data into some of the fields. */
__define_stab (N_EINCL, 0xa2, "EINCL")
/* Place holder for deleted include file.
This appears only in output from the Sun linker. */
__define_stab (N_EXCL, 0xc2, "EXCL")
/* Beginning of lexical block.
The desc is the nesting level in lexical blocks.
The value is the address of the start of the text for the block.
The variables declared inside the block *precede* the N_LBRAC symbol. */
__define_stab (N_LBRAC, 0xc0, "LBRAC")
/* End of a lexical block. Desc matches the N_LBRAC's desc.
The value is the address of the end of the text for the block. */
__define_stab (N_RBRAC, 0xe0, "RBRAC")
/* Begin named common block. Only the name is significant. */
__define_stab (N_BCOMM, 0xe2, "BCOMM")
/* Begin named common block. Only the name is significant
(and it should match the N_BCOMM). */
__define_stab (N_ECOMM, 0xe4, "ECOMM")
/* End common (local name): value is address.
I'm not sure how this is used. */
__define_stab (N_ECOML, 0xe8, "ECOML")
/* Second symbol entry containing a length-value for the preceding entry.
The value is the length. */
__define_stab (N_LENG, 0xfe, "LENG")
/* Global symbol in Pascal.
Supposedly the value is its line number; I'm skeptical. */
__define_stab (N_PC, 0x30, "PC")
/* Modula-2 compilation unit. Can someone say what info it contains? */
__define_stab (N_M2C, 0x42, "M2C")
/* Modula-2 scope information. Can someone say what info it contains? */
__define_stab (N_SCOPE, 0xc4, "SCOPE")

View File

@@ -0,0 +1,16 @@
#ifndef __GNU_STAB__
/* Indicate the GNU stab.h is in use. */
#define __GNU_STAB__
#define __define_stab(NAME, CODE, STRING) NAME=CODE,
enum __stab_debug_code
{
#include "stab.def"
};
#undef __define_stab
#endif /* __GNU_STAB_ */

View File

@@ -0,0 +1,789 @@
/* strip certain symbols from a rel file.
Copyright (C) 1986 Free Software Foundation, Inc.
NO WARRANTY
BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT
WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,
RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS"
WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY
AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
CORRECTION.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY
WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE
LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR
OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR
DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR
A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS
PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
GENERAL PUBLIC LICENSE TO COPY
1. You may copy and distribute verbatim copies of this source file
as you receive it, in any medium, provided that you conspicuously
and appropriately publish on each copy a valid copyright notice
"Copyright (C) 1986 Free Software Foundation, Inc.", and include
following the copyright notice a verbatim copy of the above disclaimer
of warranty and of this License.
2. You may modify your copy or copies of this source file or
any portion of it, and copy and distribute such modifications under
the terms of Paragraph 1 above, provided that you also do the following:
a) cause the modified files to carry prominent notices stating
that you changed the files and the date of any change; and
b) cause the whole of any work that you distribute or publish,
that in whole or in part contains or is a derivative of this
program or any part thereof, to be licensed at no charge to all
third parties on terms identical to those contained in this
License Agreement (except that you may choose to grant more extensive
warranty protection to some or all third parties, at your option).
c) You may charge a distribution fee for the physical act of
transferring a copy, and you may at your option offer warranty
protection in exchange for a fee.
Mere aggregation of another unrelated program with this program (or its
derivative) on a volume of a storage or distribution medium does not bring
the other program under the scope of these terms.
3. You may copy and distribute this program (or a portion or derivative
of it, under Paragraph 2) in object code or executable form under the terms
of Paragraphs 1 and 2 above provided that you also do one of the following:
a) accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of
Paragraphs 1 and 2 above; or,
b) accompany it with a written offer, valid for at least three
years, to give any third party free (except for a nominal
shipping charge) a complete machine-readable copy of the
corresponding source code, to be distributed under the terms of
Paragraphs 1 and 2 above; or,
c) accompany it with the information you received as to where the
corresponding source code may be obtained. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form alone.)
For an executable file, complete source code means all the source code for
all modules it contains; but, as a special exception, it need not include
source code for modules which are standard libraries that accompany the
operating system on which the executable file runs.
4. You may not copy, sublicense, distribute or transfer this program
except as expressly provided under this License Agreement. Any attempt
otherwise to copy, sublicense, distribute or transfer this program is void and
your rights to use the program under this License agreement shall be
automatically terminated. However, parties who have received computer
software programs from you with this License Agreement will not have
their licenses terminated so long as such parties remain in full compliance.
5. If you wish to incorporate parts of this program into other free
programs whose distribution conditions are different, write to the Free
Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not yet
worked out a simple rule that can be stated here, but we will often permit
this. We will be guided by the two goals of preserving the free status of
all derivatives of our free software and of promoting the sharing and reuse of
software.
In other words, you are welcome to use, share and improve this program.
You are forbidden to forbid anyone else to use, share and improve
what you give them. Help stamp out software-hoarding! */
#include <stdio.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/stat.h>
#ifdef USG
#include <fcntl.h>
#include <string.h>
#else
#include <strings.h>
#endif
#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
/* If BSD, we can use `ftruncate'. */
#ifndef USG
#define HAVE_FTRUNCATE
#endif
/* Struct or union for header of object file. */
#define HEADER_TYPE struct exec
/* Count the number of nlist entries that are for local symbols. */
int local_sym_count;
/* Count number of nlist entries that are for local symbols
whose names don't start with L. */
int non_L_local_sym_count;
/* Count the number of nlist entries for debugger info. */
int debugger_sym_count;
/* Count the number of global symbols referenced or defined. */
int global_sym_count;
/* Total number of symbols to be preserved in the current file. */
int nsyms;
/* Number of files specified in the command line. */
int number_of_files;
/* Each specified file has a file_entry structure for it.
These are contained in the vector which file_table points to. */
struct file_entry {
char *filename;
HEADER_TYPE header; /* the file's header */
int ss_size; /* size, in bytes, of symbols_and_strings data */
struct nlist *symbols_and_strings;
};
struct file_entry *file_table;
/* Descriptor on which current file is open. */
int input_desc;
/* Stream for writing that file using stdio. */
FILE *outstream;
/* 1 => strip all symbols; 2 => strip all debugger symbols */
int strip_symbols;
/* 1 => discard locals starting with L; 2 => discard all locals */
int discard_locals;
void strip_file ();
int file_open ();
void rewrite_file_symbols(), file_close();
int read_header (), read_entry_symbols (), read_file_symbols ();
void count_file_symbols ();
char *concat ();
main (argc, argv)
char **argv;
int argc;
{
int c;
extern int optind;
struct file_entry *p;
int i;
strip_symbols = 0; /* default is to strip everything. */
discard_locals = 0;
while ((c = getopt (argc, argv, "sSxX")) != EOF)
switch (c)
{
case 's':
strip_symbols = 1;
break;
case 'S':
strip_symbols = 2;
break;
case 'x':
discard_locals = 2;
break;
case 'X':
discard_locals = 1;
break;
}
/* Default is to strip all symbols. */
if (strip_symbols == 0 && discard_locals == 0)
strip_symbols = 1;
number_of_files = argc - optind;
if (!number_of_files)
fatal ("no files specified", 0);
p = file_table
= (struct file_entry *) xmalloc (number_of_files * sizeof (struct file_entry));
/* Now fill in file_table */
for (i = 0; i < number_of_files; i++)
{
p->filename = argv[i + optind];
p->symbols_and_strings = 0;
p++;
}
for (i = 0; i < number_of_files; i++)
strip_file (&file_table[i]);
}
/* process one input file */
void
strip_file (entry)
struct file_entry *entry;
{
int val;
local_sym_count = 0;
non_L_local_sym_count = 0;
debugger_sym_count = 0;
global_sym_count = 0;
val = file_open (entry);
if (val < 0)
return;
if (strip_symbols != 1)
/* Read in the existing symbols unless we are discarding everything. */
{
if (read_file_symbols (entry) < 0)
return;
}
rewrite_file_symbols (entry);
if (strip_symbols != 1)
free (entry->symbols_and_strings);
file_close ();
}
/** Convenient functions for operating on one or all files being processed. */
/* Close the file that is now open. */
void
file_close ()
{
close (input_desc);
input_desc = 0;
}
/* Open the file specified by 'entry', and return a descriptor.
The descriptor is also saved in input_desc. */
/* JF this also makes sure the file is in rel format */
int
file_open (entry)
struct file_entry *entry;
{
int desc;
int len, magicnum;
desc = open (entry->filename, O_RDWR, 0);
if (desc > 0)
{
input_desc = desc;
#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 (input_desc, (char *)&magicnum, sizeof magicnum);
if (len != sizeof magicnum)
{
error_with_file ("failure reading header", entry);
return -1;
}
if (N_BADMAG (*((struct exec *)&magicnum)))
{
error_with_file ("malformed input file (not an object file)", entry);
return -1;
}
if (read_header (desc, &entry->header, entry) < 0)
return -1;
return desc;
}
perror_file (entry);
return -1;
}
/* Print the filename of ENTRY on OUTFILE (a stdio stream), then a newline. */
prline_file_name (entry, outfile)
struct file_entry *entry;
FILE *outfile;
{
print_file_name (entry, outfile);
fprintf (outfile, "\n");
}
/* Print the filename of ENTRY on OUTFILE (a stdio stream). */
print_file_name (entry, outfile)
struct file_entry *entry;
FILE *outfile;
{
fprintf (outfile, "%s", entry->filename);
}
/* Validate file ENTRY and read its symbol and string sections into core. */
int
read_file_symbols (entry)
struct file_entry *entry;
{
if (read_entry_symbols (input_desc, entry) < 0)
return -1;
count_file_symbols (entry);
return 0;
}
/* Read a file's header into the proper place in the file_entry.
Return -1 on failure. */
int
read_header (desc, loc, entry)
int desc;
struct exec *loc;
struct file_entry *entry;
{
int len;
lseek (desc, 0, 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, loc, sizeof (struct exec));
if (len != sizeof (struct exec))
{
error_with_file ("failure reading header", entry);
return -1;
}
if (N_BADMAG (*loc))
{
error_with_file ("bad magic number", entry);
return -1;
}
return 0;
}
/* Read the symbols and strings of file ENTRY into core.
Assume it is already open, on descriptor DESC.
Return -1 on failure. */
int
read_entry_symbols (desc, entry)
struct file_entry *entry;
int desc;
{
int string_size;
lseek (desc, N_STROFF (entry->header), 0);
if (sizeof string_size != read (desc, &string_size, sizeof string_size))
{
error_with_file ("bad string table", entry);
return -1;
}
entry->ss_size = string_size + entry->header.a_syms;
entry->symbols_and_strings = (struct nlist *) xmalloc (entry->ss_size);
lseek (desc, N_SYMOFF (entry->header), 0);
if (entry->ss_size != read (desc, entry->symbols_and_strings, entry->ss_size))
{
error_with_file ("premature end of file in symbols/strings", entry);
return -1;
}
return 0;
}
/* Count the number of symbols of various categories in the file of ENTRY. */
void
count_file_symbols (entry)
struct file_entry *entry;
{
struct nlist *p, *end = entry->symbols_and_strings + entry->header.a_syms / sizeof (struct nlist);
char *name_base = entry->header.a_syms + (char *) entry->symbols_and_strings;
for (p = entry->symbols_and_strings; p < end; p++)
if (p->n_type & N_EXT)
global_sym_count++;
else if (p->n_un.n_strx && !(p->n_type & (N_STAB | N_EXT)))
{
if ((p->n_un.n_strx + name_base)[0] != 'L')
non_L_local_sym_count++;
local_sym_count++;
}
else debugger_sym_count++;
}
void write_file_syms (), modify_relocation ();
/* Total size of string table strings allocated so far */
int strtab_size;
/* Vector whose elements are the strings to go in the string table */
char **strtab_vector;
/* Index in strtab_vector at which the next string will be stored */
int strtab_index;
int sym_written_count;
int
assign_string_table_index (name)
char *name;
{
int index = strtab_size;
strtab_size += strlen (name) + 1;
strtab_vector[strtab_index++] = name;
return index;
}
void
rewrite_file_symbols (entry)
struct file_entry *entry;
{
int i;
struct nlist *newsyms;
/* Calculate number of symbols to be preserved. */
if (strip_symbols == 1)
nsyms = 0;
else
{
nsyms = global_sym_count;
if (discard_locals == 1)
nsyms += non_L_local_sym_count;
else if (discard_locals == 0)
nsyms += local_sym_count;
}
if (strip_symbols == 0)
nsyms += debugger_sym_count;
strtab_vector = (char **) xmalloc (nsyms * sizeof (char *));
strtab_index = 0;
strtab_size = 4;
/* Accumulate in 'newsyms' the symbol table to be written. */
newsyms = (struct nlist *) xmalloc (nsyms * sizeof (struct nlist));
sym_written_count = 0;
if (strip_symbols != 1)
/* Write into newsyms the symbols we want to keep. */
write_file_syms (entry, newsyms);
if (sym_written_count != nsyms)
{
fprintf (stderr, "written = %d, expected = %d\n",
sym_written_count, nsyms);
abort ();
}
/* Modify the symbol-numbers in the relocation in the file,
to preserve its meaning */
modify_relocation (input_desc, entry);
#ifndef HAVE_FTRUNCATE
{
int size = N_SYMOFF (entry->header), mode;
char *renamed = (char *)concat ("~", entry->filename, "~");
char *copy_buffer = (char *)xmalloc (size);
struct stat statbuf;
lseek (input_desc, 0, 0);
if (read (input_desc, copy_buffer, size) != size)
{
error_with_file ("can't read up to symbol table", entry);
return;
}
mode = fstat (input_desc, &statbuf) ? 0666 : statbuf.st_mode;
if (rename (entry->filename, renamed))
{
perror_file (entry);
return;
}
input_desc = creat (entry->filename, mode);
if (input_desc < 0)
{
perror_file (entry);
return;
}
if (write (input_desc, copy_buffer, size) != size)
perror_file (entry);
if (unlink (renamed))
perror_name (renamed);
free (copy_buffer);
free (renamed);
}
#endif /* not HAVE_FTRUNCATE */
/* Now write contents of NEWSYMS into the file. */
lseek (input_desc, N_SYMOFF (entry->header), 0);
write (input_desc, newsyms, nsyms * sizeof (struct nlist));
free (newsyms);
/* Now write the string table. */
{
char *strvec = (char *) xmalloc (strtab_size);
char *p;
*((long *) strvec) = strtab_size;
p = strvec + sizeof (long);
for (i = 0; i < strtab_index; i++)
{
int len = strlen (strtab_vector[i]);
strcpy (p, strtab_vector[i]);
*(p+len) = 0;
p += len + 1;
}
write (input_desc, strvec, strtab_size);
free (strvec);
}
/* Adjust file to be smaller */
#ifdef HAVE_FTRUNCATE
if (ftruncate (input_desc, tell (input_desc)) < 0)
perror_file (entry);
#endif
/* Write new symbol table size into file header. */
entry->header.a_syms = nsyms * sizeof (struct nlist);
lseek (input_desc, 0, 0);
write (input_desc, &entry->header, sizeof (struct exec));
free (strtab_vector);
}
/* Copy into NEWSYMS the symbol entries to be preserved.
Count them in sym_written_count. */
/* We record, for each symbol written, its symbol number in the resulting file.
This is so that the relocation can be updated later.
Since the symbol names will not be needed again,
this index goes in the `n_strx' field.
If a symbol is not written, -1 is stored there. */
void
write_file_syms (entry, newsyms)
struct file_entry *entry;
struct nlist *newsyms;
{
struct nlist *p = entry->symbols_and_strings;
struct nlist *end = p + entry->header.a_syms / sizeof (struct nlist);
char *string_base = (char *) end; /* address of start of file's string table */
struct nlist *outp = newsyms;
for (; p < end; p++)
{
int type = p->n_type;
int write;
if (p->n_type & N_EXT)
write = 1;
else if (p->n_un.n_strx && !(p->n_type & (N_STAB | N_EXT)))
/* ordinary local symbol */
write = (discard_locals != 2)
&& !(discard_locals == 1 &&
(p->n_un.n_strx + string_base)[0] == 'L');
else
/* debugger symbol */
write = (strip_symbols == 0);
if (write)
{
if (p->n_un.n_strx)
p->n_un.n_strx = assign_string_table_index (p->n_un.n_strx + string_base);
*outp++ = *p;
p->n_un.n_strx = sym_written_count++;
}
else p->n_un.n_strx = -1;
}
}
/* Read in ENTRY's relocation, alter the symbolnums in it,
and write it out again. */
void
modify_relocation (desc, entry)
int desc;
struct file_entry *entry;
{
struct relocation_info *reloc, *p, *end;
int size = entry->header.a_trsize + entry->header.a_drsize;
struct nlist *sym_base = (struct nlist *) entry->symbols_and_strings;
int losing = 0;
reloc = (struct relocation_info *) xmalloc (size);
lseek (desc, N_TXTOFF (entry->header) + entry->header.a_text + entry->header.a_data, 0);
read (desc, reloc, size);
p = reloc;
end = (struct relocation_info *) (size + (char *) reloc);
while (p < end)
{
if (p->r_extern)
{
int newnum = (sym_base == 0 ? -1
:(sym_base + p->r_symbolnum) -> n_un.n_strx);
if (newnum < 0)
{
if (losing == 0)
error_with_file ("warning: file is now unlinkable", entry);
losing = 1;
}
p->r_symbolnum = newnum;
}
p++;
}
lseek (desc, N_TXTOFF (entry->header) + entry->header.a_text + entry->header.a_data, 0);
write (desc, reloc, size);
}
/* Report a fatal error.
STRING is a printf format string and ARG is one arg for it. */
fatal (string, arg)
char *string, *arg;
{
fprintf (stderr, "strip: ");
fprintf (stderr, string, arg);
fprintf (stderr, "\n");
exit (1);
}
/* Report an error using the message for the last failed system call,
followed by the string NAME. */
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);
}
/* Report an error using the message for the last failed system call,
followed by the name of file ENTRY. */
perror_file (entry)
struct file_entry *entry;
{
extern int errno, sys_nerr;
extern char *sys_errlist[];
char *s;
if (errno < sys_nerr)
s = sys_errlist[errno];
else
s = "cannot open";
error_with_file (s, entry);
}
/* Report an error. STRING is printed, and the filename of ENTRY. */
error_with_file (string, entry, arg1, arg2)
char *string;
struct file_entry *entry;
int arg1, arg2;
{
fprintf (stderr, "strip: ");
print_file_name (entry, stderr);
fprintf (stderr, ": ");
fprintf (stderr, string, arg1, arg2);
fprintf (stderr, "\n");
}
/* Report a nonfatal error.
STRING is a format for printf, and ARG1 ... ARG3 are args for it. */
error (string, arg1, arg2, arg3)
char *string, *arg1, *arg2, *arg3;
{
fprintf (stderr, string, arg1, arg2, arg3);
fprintf (stderr, "\n");
}
/* 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;
}
/* Like malloc but get fatal error if memory is exhausted. */
int
xmalloc (size)
int size;
{
int result = malloc (size);
if (!result)
fatal ("virtual memory exhausted", 0);
return result;
}
#ifdef USG
rename (from, to)
char *from, *to;
{
if (unlink (to) < 0
|| link (from, to) < 0
|| unlink (from) < 0)
return -1;
else
return 0;
}
#endif

View File

@@ -0,0 +1,477 @@
/* GDB symbol table format definitions.
Copyright (C) 1986 Free Software Foundation, Inc.
Hacked by Michael Tiemann (tiemann@mcc.com)
GDB is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY. No author or distributor accepts responsibility to anyone
for the consequences of using it or for whether it serves any
particular purpose or works at all, unless he says so in writing.
Refer to the GDB General Public License for full details.
Everyone is granted permission to copy, modify and redistribute GDB,
but only under the conditions described in the GDB General Public
License. A copy of this license is supposed to have been given to you
along with GDB so you can know your rights and responsibilities. It
should be in a file named COPYING. Among other things, the copyright
notice and this notice must be preserved on all copies.
In other words, go ahead and share GDB, but don't try to stop
anyone else from sharing it farther. Help stamp out software hoarding!
*/
/* Format of GDB symbol table data.
There is one symbol segment for each source file or
independant compilation. These segments are simply concatenated
to form the GDB symbol table. A zero word where the beginning
of a segment is expected indicates there are no more segments.
Format of a symbol segment:
The symbol segment begins with a word containing 1
if it is in the format described here. Other formats may
be designed, with other code numbers.
The segment contains many objects which point at each other.
The pointers are offsets in bytes from the beginning of the segment.
Thus, each segment can be loaded into core and its pointers relocated
to make valid in-core pointers.
All the data objects in the segment can be found indirectly from
one of them, the root object, of type `struct symbol_root'.
It appears at the beginning of the segment.
The total size of the segment, in bytes, appears as the `length'
field of this object. This size includes the size of the
root object.
All the object data types are defined here to contain pointer types
appropriate for in-core use on a relocated symbol segment.
Casts to and from type int are required for working with
unrelocated symbol segments such as are found in the file.
The ldsymaddr word is filled in by the loader to contain
the offset (in bytes) within the ld symbol table
of the first nonglobal symbol from this compilation.
This makes it possible to match those symbols
(which contain line number information) reliably with
the segment they go with.
Core addresses within the program that appear in the symbol segment
are not relocated by the loader. They are inserted by the assembler
and apply to addresses as output by the assembler, so GDB must
relocate them when it loads the symbol segment. It gets the information
on how to relocate from the textrel, datarel, bssrel, databeg and bssbeg
words of the root object.
The words textrel, datarel and bssrel
are filled in by ld with the amounts to relocate within-the-file
text, data and bss addresses by; databeg and bssbeg can be
used to tell which kind of relocation an address needs. */
enum language {language_c};
struct symbol_root
{
int format; /* Data format version */
int length; /* # bytes in this symbol segment */
int ldsymoff; /* Offset in ld symtab of this file's syms */
int textrel; /* Relocation for text addresses */
int datarel; /* Relocation for data addresses */
int bssrel; /* Relocation for bss addresses */
char *filename; /* Name of main source file compiled */
char *filedir; /* Name of directory it was reached from */
struct blockvector *blockvector; /* Vector of all symbol-naming blocks */
struct typevector *typevector; /* Vector of all data types */
enum language language; /* Code identifying the language used */
char *version; /* Version info. Not fully specified */
char *compilation; /* Compilation info. Not fully specified */
int databeg; /* Address within the file of data start */
int bssbeg; /* Address within the file of bss start */
struct sourcevector *sourcevector; /* Vector of line-number info */
};
/* All data types of symbols in the compiled program
are represented by `struct type' objects.
All of these objects are pointed to by the typevector.
The type vector may have empty slots that contain zero. */
struct typevector
{
int length; /* Number of types described */
struct type *type[1];
};
/* Different kinds of data types are distinguished by the `code' field. */
enum type_code
{
TYPE_CODE_UNDEF, /* Not used; catches errors */
TYPE_CODE_PTR, /* Pointer type */
TYPE_CODE_ARRAY, /* Array type, lower bound zero */
TYPE_CODE_STRUCT, /* C struct or Pascal record */
TYPE_CODE_UNION, /* C union or Pascal variant part */
TYPE_CODE_ENUM, /* Enumeration type */
TYPE_CODE_FUNC, /* Function type */
TYPE_CODE_INT, /* Integer type */
TYPE_CODE_FLT, /* Floating type */
TYPE_CODE_VOID, /* Void type (values zero length) */
TYPE_CODE_SET, /* Pascal sets */
TYPE_CODE_RANGE, /* Range (integers within spec'd bounds) */
TYPE_CODE_PASCAL_ARRAY, /* Array with explicit type of index */
/* C++ */
TYPE_CODE_MEMBER, /* Member type */
TYPE_CODE_REF, /* C++ Reference types */
};
/* This appears in a type's flags word for an unsigned integer type. */
#define TYPE_FLAG_UNSIGNED 1
/* Other flag bits are used with GDB. */
#define TYPE_FLAG_HAS_CONSTRUCTOR 256
#define TYPE_FLAG_HAS_DESTRUCTOR 512
#define TYPE_FLAG_VIA_PUBLIC 1024
#define TYPE_FLAG_VIA_VIRTUAL 2048
struct type
{
/* Code for kind of type */
enum type_code code;
/* Name of this type, or zero if none.
This is used for printing only.
Type names specified as input are defined by symbols. */
char *name;
/* Length in bytes of storage for a value of this type */
int length;
/* For a pointer type, describes the type of object pointed to.
For an array type, describes the type of the elements.
For a function type, describes the type of the value.
Unused otherwise. */
struct type *target_type;
/* Type that is a pointer to this type.
Zero if no such pointer-to type is known yet.
The debugger may add the address of such a type
if it has to construct one later. */
struct type *pointer_type;
/* C++: also need a reference type. */
struct type *reference_type;
/* Type that is a function returning this type.
Zero if no such function type is known here.
The debugger may add the address of such a type
if it has to construct one later. */
struct type *function_type;
/* Handling of pointers to members:
TYPE_MAIN_VARIANT is used for pointer and pointer
to member types. Normally it the value of the address of its
containing type. However, for pointers to members, we must be
able to allocate pointer to member types and look them up
from some place of reference.
NEXT_VARIANT is the next element in the chain. */
struct type *main_variant, *next_variant;
/* Flags about this type. */
short flags;
/* Number of fields described for this type */
short nfields;
/* For structure and union types, a description of each field.
For set and pascal array types, there is one "field",
whose type is the domain type of the set or array.
For range types, there are two "fields",
the minimum and maximum values (both inclusive).
For enum types, each possible value is described by one "field".
For range types, there are two "fields", that record constant values
(inclusive) for the minimum and maximum.
Using a pointer to a separate array of fields
allows all types to have the same size, which is useful
because we can allocate the space for a type before
we know what to put in it. */
struct field
{
/* Position of this field, counting in bits from start of
containing structure. For a function type, this is the
position in the argument list of this argument.
For a range bound or enum value, this is the value itself. */
int bitpos;
/* Size of this field, in bits, or zero if not packed.
For an unpacked field, the field's type's length
says how many bytes the field occupies. */
int bitsize;
/* In a struct or enum type, type of this field.
In a function type, type of this argument.
In an array type, the domain-type of the array. */
struct type *type;
/* Name of field, value or argument.
Zero for range bounds and array domains. */
char *name;
} *fields;
/* C++ */
int *private_field_bits;
int *protected_field_bits;
/* Number of methods described for this type */
short nfn_fields;
/* Number of base classes this type derives from. */
short n_baseclasses;
/* Number of methods described for this type plus all the
methods that it derives from. */
int nfn_fields_total;
/* For classes, structures, and unions, a description of each field,
which consists of an overloaded name, followed by the types of
arguments that the method expects, and then the name after it
has been renamed to make it distinct. */
struct fn_fieldlist
{
/* The overloaded name. */
char *name;
/* The number of methods with this name. */
int length;
/* The list of methods. */
struct fn_field
{
#if 0
/* The overloaded name */
char *name;
#endif
/* The type of the argument */
struct type *type;
/* The argument list */
struct type **args;
/* The name after it has been processed */
char *physname;
/* If this is a virtual function, the offset into the vtbl-1,
else 0. */
int voffset;
} *fn_fields;
int *private_fn_field_bits;
int *protected_fn_field_bits;
} *fn_fieldlists;
unsigned char via_protected;
unsigned char via_public;
/* For types with virtual functions, VPTR_BASETYPE is the base class which
defined the virtual function table pointer. VPTR_FIELDNO is
the field number of that pointer in the structure.
For types that are pointer to member types, VPTR_BASETYPE
ifs the type that this pointer is a member of.
Unused otherwise. */
struct type *vptr_basetype;
int vptr_fieldno;
/* If this type has a base class, put it here.
If this type is a pointer type, the chain of member pointer
types goes here.
Unused otherwise. */
struct type **baseclasses;
};
/* All of the name-scope contours of the program
are represented by `struct block' objects.
All of these objects are pointed to by the blockvector.
Each block represents one name scope.
Each lexical context has its own block.
The first two blocks in the blockvector are special.
The first one contains all the symbols defined in this compilation
whose scope is the entire program linked together.
The second one contains all the symbols whose scope is the
entire compilation excluding other separate compilations.
In C, these correspond to global symbols and static symbols.
Each block records a range of core addresses for the code that
is in the scope of the block. The first two special blocks
give, for the range of code, the entire range of code produced
by the compilation that the symbol segment belongs to.
The blocks appear in the blockvector
in order of increasing starting-address,
and, within that, in order of decreasing ending-address.
This implies that within the body of one function
the blocks appear in the order of a depth-first tree walk. */
struct blockvector
{
/* Number of blocks in the list. */
int nblocks;
/* The blocks themselves. */
struct block *block[1];
};
struct block
{
/* Addresses in the executable code that are in this block.
Note: in an unrelocated symbol segment in a file,
these are always zero. They can be filled in from the
N_LBRAC and N_RBRAC symbols in the loader symbol table. */
int startaddr, endaddr;
/* The symbol that names this block,
if the block is the body of a function;
otherwise, zero.
Note: In an unrelocated symbol segment in an object file,
this field may be zero even when the block has a name.
That is because the block is output before the name
(since the name resides in a higher block).
Since the symbol does point to the block (as its value),
it is possible to find the block and set its name properly. */
struct symbol *function;
/* The `struct block' for the containing block, or 0 if none. */
/* Note that in an unrelocated symbol segment in an object file
this pointer may be zero when the correct value should be
the second special block (for symbols whose scope is one compilation).
This is because the compiler ouptuts the special blocks at the
very end, after the other blocks. */
struct block *superblock;
/* A flag indicating whether or not the fucntion corresponding
to this block was compiled with gcc or not. If there is no
function corresponding to this block, this meaning of this flag
is undefined. (In practice it will be 1 if the block was created
while processing a file compiled with gcc and 0 when not). */
unsigned char gcc_compile_flag;
/* Number of local symbols. */
int nsyms;
/* The symbols. */
struct symbol *sym[1];
};
/* Represent one symbol name; a variable, constant, function or typedef. */
/* Different name spaces for symbols. Looking up a symbol specifies
a namespace and ignores symbol definitions in other name spaces.
VAR_NAMESPACE is the usual namespace.
In C, this contains variables, function names, typedef names
and enum type values.
STRUCT_NAMESPACE is used in C to hold struct, union and enum type names.
Thus, if `struct foo' is used in a C program,
it produces a symbol named `foo' in the STRUCT_NAMESPACE.
LABEL_NAMESPACE may be used for names of labels (for gotos);
currently it is not used and labels are not recorded at all. */
/* For a non-global symbol allocated statically,
the correct core address cannot be determined by the compiler.
The compiler puts an index number into the symbol's value field.
This index number can be matched with the "desc" field of
an entry in the loader symbol table. */
enum namespace
{
UNDEF_NAMESPACE, VAR_NAMESPACE, STRUCT_NAMESPACE, LABEL_NAMESPACE,
};
/* An address-class says where to find the value of the symbol in core. */
enum address_class
{
LOC_UNDEF, /* Not used; catches errors */
LOC_CONST, /* Value is constant int */
LOC_STATIC, /* Value is at fixed address */
LOC_REGISTER, /* Value is in register */
LOC_ARG, /* Value is at spec'd position in arglist */
LOC_REGPARM, /* Value is at spec'd position in register window */
LOC_LOCAL, /* Value is at spec'd pos in stack frame */
LOC_TYPEDEF, /* Value not used; definition in SYMBOL_TYPE
Symbols in the namespace STRUCT_NAMESPACE
all have this class. */
LOC_LABEL, /* Value is address in the code */
LOC_BLOCK, /* Value is address of a `struct block'.
Function names have this class. */
LOC_EXTERNAL, /* Value is at address not in this compilation.
This is used for .comm symbols
and for extern symbols within functions.
Inside GDB, this is changed to LOC_STATIC once the
real address is obtained from a loader symbol. */
LOC_CONST_BYTES /* Value is a constant byte-sequence. */
};
struct symbol
{
/* Symbol name */
char *name;
/* Name space code. */
enum namespace namespace;
/* Address class */
enum address_class class;
/* Data type of value */
struct type *type;
/* constant value, or address if static, or register number,
or offset in arguments, or offset in stack frame. */
union
{
long value;
struct block *block; /* for LOC_BLOCK */
char *bytes; /* for LOC_CONST_BYTES */
}
value;
};
struct partial_symbol
{
/* Symbol name */
char *name;
/* Name space code. */
enum namespace namespace;
/* Address class (for info_symbols) */
enum address_class class;
};
/*
* Vectors of all partial symbols read in from file; actually declared
* and used in dbxread.c.
*/
extern struct partial_symbol *global_psymbols, *static_psymbols;
/* Source-file information.
This describes the relation between source files and line numbers
and addresses in the program text. */
struct sourcevector
{
int length; /* Number of source files described */
struct source *source[1]; /* Descriptions of the files */
};
/* Each item represents a line-->pc (or the reverse) mapping. This is
somewhat more wasteful of space than one might wish, but since only
the files which are actually debugged are read in to core, we don't
waste much space.
Each item used to be an int; either minus a line number, or a
program counter. If it represents a line number, that is the line
described by the next program counter value. If it is positive, it
is the program counter at which the code for the next line starts. */
struct linetable_entry
{
int line;
CORE_ADDR pc;
};
struct linetable
{
int nitems;
struct linetable_entry item[1];
};
/* All the information on one source file. */
struct source
{
char *name; /* Name of file */
struct linetable contents;
};