veench@cs.vu.nl (Veen van CH) (03/03/88)
In this article and the preceding article is an implementation of the profil system call for PC-MINIX. All diffs are relative to MINIX 1.2. See the README file and man pages for more information. Dick van Veen #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # lib/a.out.h # lib/end.s # lib/make # lib/monitor.c # lib/monstart.c # lib/mrtso.s # lib/profil.c # man/ast.doc # man/nm.doc # man/prof.doc # man/strip.doc # src/ast.c # src/cc1.1.c.diff # src/cc1.2.c.diff # src/nm.c # src/prof.c # src/strip.c # This archive created: Wed Mar 02 09:02:13 1988 export PATH; PATH=/bin:/usr/bin:$PATH echo shar: "extracting 'lib/a.out.h'" '(3646 characters)' if test -f 'lib/a.out.h' then echo shar: "will not over-write existing file 'lib/a.out.h'" else cat << \SHAR_EOF > 'lib/a.out.h' /* a.out header file */ struct exec { /* a.out header */ unsigned char a_magic[2]; /* magic number */ unsigned char a_flags; /* flags, see below */ unsigned char a_cpu; /* cpu id */ unsigned char a_hdrlen; /* length of header */ unsigned char a_unused; /* reserved for future use */ unsigned short a_version; /* version stamp */ /* not used */ long a_text; /* size of text segement in bytes */ long a_data; /* size of data segment in bytes */ long a_bss; /* size of bss segment in bytes */ long a_no_entry; /* in fact: entry point, a_entry */ long a_total; /* total memory allocated */ long a_syms; /* size of symbol table */ /* SHORT FORM ENDS HERE */ long a_trsize; /* text relocation size */ long a_drsize; /* data relocation size */ long a_tbase; /* text relocation base */ long a_dbase; /* data relocation base */ }; #define A_MAGIC0 (unsigned char) 0x01 #define A_MAGIC1 (unsigned char) 0x03 #define BADMAG(X) ((X).a_magic[0] != A_MAGIC0 ||\ (X).a_magic[1] != A_MAGIC1) /* CPU Id of TARGET machine */ /* byte order coded in low order two bits */ #define A_NONE 0x00 /* unknown */ #define A_I8086 0x04 /* intel i8086/8088 */ #define A_M68K 0x0B /* motorola m68000 */ #define A_NS16K 0x0C /* national semiconductor 16032 */ #define A_BLR(cputype) ((cputype&0x01)!=0) /* TRUE if bytes left-to-right */ #define A_WLR(cputype) ((cputype&0x02)!=0) /* TRUE if words left-to-right */ /* flags: */ #define A_EXEC 0x10 /* executable */ #define A_SEP 0x20 /* separate I/D */ #define A_PURE 0x40 /* pure text */ /* not used */ #define A_TOVLY 0x80 /* text overlay */ /* not used */ /* offsets of various things: */ #define A_MINHDR 32 #define A_TEXTPOS(X) ((long)(X).a_hdrlen) #define A_DATAPOS(X) (A_TEXTPOS(X) + (X).a_text) #define A_HASRELS(X) ((X).a_hdrlen > (unsigned char) A_MINHDR) #define A_HASEXT(X) ((X).a_hdrlen > (unsigned char) (A_MINHDR + 8)) #define A_HASLNS(X) ((X).a_hdrlen > (unsigned char) (A_MINHDR + 16)) #define A_HASTOFF(X) ((X).a_hdrlen > (unsigned char) (A_MINHDR + 24)) #define A_TRELPOS(X) (A_DATAPOS(X) + (X).a_data) #define A_DRELPOS(X) (A_TRELPOS(X) + (X).a_trsize) #define A_SYMPOS(X) (A_TRELPOS(X) + (A_HASRELS(X) ? \ ((X).a_trsize + (X).a_drsize) : 0)) struct reloc { long r_vaddr; /* virtual address of reference */ unsigned short r_symndx; /* internal segnum or extern symbol num */ unsigned short r_type; /* relocation type */ }; /* r_tyep values: */ #define R_ABBS 0 #define R_RELLBYTE 2 #define R_PCRBYTE 3 #define R_RELWORD 4 #define R_PCRWORD 5 #define R_RELLONG 6 #define R_PCRLONG 7 #define R_REL3BYTE 8 #define R_KBRANCHE 9 /* r_symndx for internal segments */ #define S_ABS ((unsigned short)-1) #define S_TEXT ((unsigned short)-2) #define S_DATA ((unsigned short)-3) #define S_BSS ((unsigned short)-4) struct nlist { /* symbol table entry */ char n_name[8]; /* symbol name */ long n_value; /* value */ unsigned char n_sclass; /* storage class */ unsigned char n_numaux; /* number of auxiliary entries */ /* not used */ unsigned short n_type; /* language base and derived type */ /* not used */ }; /* low bits of storage class (section) */ #define N_SECT 07 /* section mask */ #define N_UNDF 00 /* undefined */ #define N_ABS 01 /* absolute */ #define N_TEXT 02 /* text */ #define N_DATA 03 /* data */ #define N_BSS 04 /* bss */ #define N_COMM 05 /* (common) */ /* high bits of storage class */ #define N_CLASS 0370 /* storage class mask */ #define C_NULL #define C_EXT 0020 /* external symbol */ #define C_STAT 0030 /* static */ /* there are many others, but they are not supported */ SHAR_EOF fi echo shar: "extracting 'lib/end.s'" '(119 characters)' if test -f 'lib/end.s' then echo shar: "will not over-write existing file 'lib/end.s'" else cat << \SHAR_EOF > 'lib/end.s' .globl endtext, enddata, endbss, _etext, _end, _edata .text endtext: _etext: .data enddata: _edata: .bss endbss: _end: SHAR_EOF fi echo shar: "extracting 'lib/make'" '(1552 characters)' if test -f 'lib/make' then echo shar: "will not over-write existing file 'lib/make'" else cat << \SHAR_EOF > 'lib/make' ar a libc.a qsort.s popen.s system.s cleanup.s fgets.s fprintf.s puts.s ar a libc.a scanf.s monstart.s monitor.s profil.s ar a libc.a fputs.s fread.s freopen.s fclose.s fopen.s fseek.s fflush.s ar a libc.a ftell.s fwrite.s gets.s getc.s printdat.s setbuf.s sprintf.s ar a libc.a doprintf.s putc.s ungetc.s strcmp.s access.s chdir.s chmod.s ar a libc.a chown.s chroot.s creat.s dup.s dup2.s exec.s exit.s ar a libc.a fork.s isatty.s fstat.s getegid.s getenv.s geteuid.s getgid.s ar a libc.a getpass.s close.s getuid.s ioctl.s kill.s link.s lseek.s ar a libc.a malloc.s brk.s brk2.s brksize.s mknod.s mktemp.s getpid.s ar a libc.a mount.s open.s perror.s pipe.s prints.s read.s setgid.s ar a libc.a setuid.s sleep.s alarm.s pause.s signal.s catchsig.s stat.s ar a libc.a stime.s strcat.s strcpy.s strlen.s strncat.s strncmp.s strncpy.s ar a libc.a sync.s time.s times.s umask.s umount.s unlink.s utime.s ar a libc.a wait.s stderr.s write.s syslib.s call.s atoi.s message.s ar a libc.a sendrec.s printk.s abort.s itoa.s stb.s abs.s atol.s ar a libc.a ctype.s index.s bcopy.s getutil.s rand.s rindex.s setjmp.s # now the compiler routines ar a libc.a adi.s and.s cii.s cms.s cmu4.s com.s csa2.s ar a libc.a csb2.s cuu.s _dup.s dvi4.s dvu4.s exg.s fakfp.s ar a libc.a gto.s iaar.s ilar.s inn.s ior.s isar.s lar2.s ar a libc.a loi.s mli4.s mon.s nop.s rck.s rmi4.s rmu4.s ar a libc.a sar2.s sbi.s set.s sti.s strhp.s xor.s error.s ar a libc.a unknown.s fat.s trp.s stop.s ret6.s ret8.s lfr6.s ar a libc.a lfr8.s retarea.s blm.s vars.s return.s cmi4.s SHAR_EOF fi echo shar: "extracting 'lib/monitor.c'" '(940 characters)' if test -f 'lib/monitor.c' then echo shar: "will not over-write existing file 'lib/monitor.c'" else cat << \SHAR_EOF > 'lib/monitor.c' struct profhdr { int *lowpc; int *highpc; int nfunc; }; struct cnt { int *pc; long ncall; }; monitor(lowpc, highpc, buf, bufsiz, nfunc) char *lowpc, *highpc; int *buf, bufsiz, nfunc; { /* Use first two words in buffer for lowpc and highpc. */ static int *sbuf, sbufsiz; long tmp; int *tmpptr = (int *) &tmp; int fd, scale; if (lowpc == 0) { profil(0, 0, 0, 0); fd = creat("mon.out", 0666); write(fd, sbuf, sbufsiz); close(fd); return; } sbuf = buf; sbufsiz = bufsiz << 1; buf[0] = (int) lowpc; buf[1] = (int) highpc; buf[2] = nfunc; scale = sizeof(struct profhdr) + nfunc*sizeof(struct cnt); bufsiz -= scale >> 1; buf = (int *) (((int) buf) + scale); if (bufsiz <= 0) return; scale = (highpc - lowpc) >> 1; /* use integers */ if (scale > bufsiz) { tmpptr[0] = 0; tmpptr[1] = bufsiz; tmp = (tmp / scale); scale = tmpptr[0]; } else scale = 0xFFFF; profil(buf, bufsiz << 1, lowpc, scale); } SHAR_EOF fi echo shar: "extracting 'lib/monstart.c'" '(527 characters)' if test -f 'lib/monstart.c' then echo shar: "will not over-write existing file 'lib/monstart.c'" else cat << \SHAR_EOF > 'lib/monstart.c' #define NCOUNTS 0 /* no support yet */ struct profhdr { int *lowpc; int *highpc; int nfunc; }; struct cnt { int *pc; long ncall; }; monstartup(lowpc, highpc) int (*lowpc)(), (*highpc)(); { unsigned int size; char *buf, *sbrk(); size = (((unsigned int) highpc - (int) lowpc + 7) & ~7) << 1; size += NCOUNTS * sizeof(struct cnt) + sizeof(struct profhdr); buf = sbrk(size); if ((int) buf == -1) { write(2, "can't allocate monitor buffer\n", 30); return; } monitor(lowpc, highpc, buf, size >> 1, NCOUNTS); } SHAR_EOF fi echo shar: "extracting 'lib/mrtso.s'" '(1077 characters)' if test -f 'lib/mrtso.s' then echo shar: "will not over-write existing file 'lib/mrtso.s'" else cat << \SHAR_EOF > 'lib/mrtso.s' | This is the C run-time start-off routine. It's job is to take the | arguments as put on the stack by EXEC, and to parse them and set them up the | way _main expects them. .globl _main, _exit, crtso, _environ, _exit, __exit .globl begtext, begdata, begbss, endtext, enddata, endbss .text begtext: crtso: mov bx,sp mov cx,(bx) add bx,*2 mov ax,cx inc ax shl ax,#1 add ax,bx mov _environ,ax | save envp in environ push ax | push environ push bx | push argv push cx | push argc mov ax,#_etext | monstartup(2, etext) push ax mov ax,#2 push ax call _monstartup | do call of monstartup pop bx | remove arguments pop bx call _main add sp,*6 | remove arguments push ax | push exit status _exit: xor ax,ax | monitor(0); push ax call _monitor pop bx __exit: push bp | this is the exit library call mov bp,sp xor ax,ax push ax push ax push ax push ax push ax push 4(bp) mov ax,#1 push ax xor ax,ax push ax call _callm1 | this is not supposed to return .data begdata: _environ: .word 0 .bss begbss: SHAR_EOF fi echo shar: "extracting 'lib/profil.c'" '(196 characters)' if test -f 'lib/profil.c' then echo shar: "will not over-write existing file 'lib/profil.c'" else cat << \SHAR_EOF > 'lib/profil.c' #include "../include/lib.h" PUBLIC int profil(buff, bufsiz, offset, scale) char *buff; int bufsiz, offset, scale; { return callm1(MM, PROFIL, bufsiz, offset, scale, buff, NIL_PTR, NIL_PTR); } SHAR_EOF fi echo shar: "extracting 'man/ast.doc'" '(484 characters)' if test -f 'man/ast.doc' then echo shar: "will not over-write existing file 'man/ast.doc'" else cat << \SHAR_EOF > 'man/ast.doc' Command: ast - add symbol table to executable file Syntax: ast -xX [file] [symbol_file] Flags: -x do not preserve local symbols -X preserve local symbols except for those that begin with 'I' or 'L', these are compiler generated Example: ast -X a.out # add symbols from symbol.out to a.out Ast adds the symbol table produced by the -s option of asld to the executable file. The symbol table is expected in the file symbol.out, but can also be given at the command line. SHAR_EOF fi echo shar: "extracting 'man/nm.doc'" '(727 characters)' if test -f 'man/nm.doc' then echo shar: "will not over-write existing file 'man/nm.doc'" else cat << \SHAR_EOF > 'man/nm.doc' Command: nm - print name list Syntax: nm [-gnopru] [file] ... Flags: -g print only external symbols. -n sort numerically rather than alphabetically. -o prepend file name to each line rather than only once. -p don't sort, print in symbol-table order. -r sort in reverse order. -u print only undefined symbols. Example: nm -n a.out # print symbols in numerical order Nm prints the symbol table of executable files when it is available. If no file is given, the symbols in a.out are used. The format of the table is somewhat compatible with the one produced by asld when used with the -s option. The symbol table can be added with ast. NOTE: archives are not supported, assembly files don't have symbol tables. SHAR_EOF fi echo shar: "extracting 'man/prof.doc'" '(824 characters)' if test -f 'man/prof.doc' then echo shar: "will not over-write existing file 'man/prof.doc'" else cat << \SHAR_EOF > 'man/prof.doc' Command: prof - display profile data Syntax: prof [-alz] [a.out] [mon.out] Flags: -a print all symbols -l print symbols by value instead of by percentage -z print also symbols with zero count Example: prof a.out # print data collected by a.out Prof interprets the mon.out file produced by the monitor subroutine. The samples are collected, and assigned to the external symbols in the a.out file. For each symbol the percentage of time spent in executing between that symbol and the next are printed. Remember that the results are only an aproximation of the real times, and that short procedures can get to little samples. Note also that the time spent in send_rec is in fact the time spent executing the system calls. To have the mon.out file automatically produced, use the -p flag of the C-compiler. SHAR_EOF fi echo shar: "extracting 'man/strip.doc'" '(261 characters)' if test -f 'man/strip.doc' then echo shar: "will not over-write existing file 'man/strip.doc'" else cat << \SHAR_EOF > 'man/strip.doc' Command: strip - remove symbol table from executable file Syntax: strip [file] ... Example: strip a.out # remove symbols from a.out For each file argument, strip removes the symbol table. Strip makes a copy of the file being stripped, so links are lost. SHAR_EOF fi echo shar: "extracting 'src/ast.c'" '(5892 characters)' if test -f 'src/ast.c' then echo shar: "will not over-write existing file 'src/ast.c'" else cat << \SHAR_EOF > 'src/ast.c' /* ast - add symbol table. Author: Dick van Veen, veench@cs.vu.nl */ #include <a.out.h> #include <stdio.h> /* * Since the a.out file in MINIX does not contain any symbol table, * we use the symbol table produced with the -s option of asld. * * Read symbol table in memory, remove compiler generated labels, * sort the labels and add it to the a.out file. * * When finally there comes a real as and ld, we may also get * a symbol table in the a.out file, and we can forget this program. * */ /* * ast [flags] [file] [symbolfile] * * flags: * -x do not preserve local symbols * -X preserve local symbols except for those whose name begin * with 'I' or 'L', these are compiler generated. * * - when no symbol file is present, symbol.out is assumed. * - when no file is present, a.out is assumed. * - when one file name is present it must be the executable file * - just one flag may be pressent. * */ #define A_OUT "a.out" #define SYMBOL_FILE "symbol.out" /* contains symbol table */ #define LINE_LENGTH 24 #define WORTH_LESS 1 /* lines contain no symbol */ #define LAST_LINE 2 /* end of file reached */ struct exec header; /* header info of a.out file */ int x_flag; /* flags to ast */ int X_flag; int o_flag; char *s_file, *o_file; /* names of files used by ast */ FILE *s_fd, *o_fd; /* file descriptors of those files */ int nr_symbols; /* number of symbols added */ char buffer[LINE_LENGTH]; /* contains line of symbol file */ char io_buf[BUFSIZ]; /* for buffered output on stderr */ unsigned int get_value(); /* forward definition */ main(argc, argv) int argc; char **argv; { extern FILE *fopen(); argv++; if (*argv != NULL && **argv == '-') { *argv += 1; if (**argv == 'x') x_flag = 1; else if (**argv == 'X') X_flag = 1; else { fprintf(stderr, "illegal flag: -%c\n", **argv); Exit(-1); } argv++; } if (*argv != NULL) { o_file = *argv; argv++; } if (*argv != NULL) { s_file = *argv; argv++; } if (*argv != NULL) { fprintf(stderr, "Usage: ast [-{x,X}] [file] [symbolfile]\n"); Exit(-1); } if (o_file == NULL) o_file = A_OUT; o_fd = fopen(o_file, "a"); if (o_fd == NULL) { fprintf(stderr, "can't open %s\n", o_file); Exit(-1); } if (s_file == NULL) s_file = SYMBOL_FILE; s_fd = fopen(s_file, "r"); if (s_fd == NULL) { fprintf(stderr, "can't open %s\n", s_file); Exit(-1); } setbuf(s_fd, io_buf); ast(s_fd, o_fd); Exit(0); } Exit(val) int val; { _cleanup(); exit(val); } ast(s_fd, o_fd) FILE *s_fd, *o_fd; { struct nlist symbol; int line_type; do_header(); for(;;) { read_line(s_fd, buffer); line_type = transform_line(buffer, &symbol); if (line_type == WORTH_LESS) continue; if (line_type == LAST_LINE) break; save_line(o_fd, &symbol); } redo_header(o_fd); } read_line(fd, buffer) FILE *fd; char *buffer; { char ch; char *buf1; buf1 = buffer; *buffer = '\n'; ch = fgetc(fd); while (ch != '\n' && ch != EOF) { *buffer = ch; buffer++; ch = fgetc(fd); } if (ch == EOF) *buffer = '\0'; else *buffer = '\n'; buffer[1] = '\0'; } transform_line(buffer, symbol) char *buffer; struct nlist *symbol; { switch(*buffer) { case 'a': /* absolute symbol */ symbol->n_sclass = N_ABS; break; case 'A': symbol->n_sclass = N_ABS | C_EXT; break; case 'u': /* undefined symbol */ symbol->n_sclass = N_UNDF; break; case 'U': symbol->n_sclass = N_UNDF | C_EXT; break; case 't': /* text symbol */ symbol->n_sclass = N_TEXT; break; case 'T': symbol->n_sclass = N_TEXT | C_EXT; break; case 'd': symbol->n_sclass = N_DATA; case 'D': /* data symbol */ symbol->n_sclass = N_DATA | C_EXT; break; case 'b': symbol->n_sclass = N_BSS; case 'B': /* bss symbol */ symbol->n_sclass = N_BSS | C_EXT; break; case '\0': /* reached end of file */ return(LAST_LINE); default: /* one of first two lines */ return(WORTH_LESS); } if (buffer[1] != ' ') { fprintf(stderr, "illegal file format\n"); Exit(-1); } symbol->n_value = get_value(buffer + 2); if (buffer[6] != ' ') { fprintf(stderr, "illegal file format\n"); Exit(-1); } get_name(buffer + 7, symbol->n_name); return(0); /* yeah, found a symbol */ } save_line(fd, symbol) FILE *fd; struct nlist *symbol; { if (!(symbol->n_sclass & C_EXT)) { /* local symbol */ if (x_flag) return; if (X_flag && (symbol->n_name[0] == 'I' || symbol->n_name[0] == 'L') return; } if (fwrite(symbol, sizeof(struct nlist), 1, fd) != 1) { fprintf(stderr, "can't write %s\n", o_file); Exit(-1); } nr_symbols++; } unsigned get_value(string) char *string; { unsigned value; int shift, bits; value = 0; for (shift = 0; shift < 16; shift += 4) { bits = get_bits(*string); value = (value << 4) | bits; string++; } return(value); } get_bits(ch) char ch; { if (ch >= '0' && ch <= '9') return (ch - '0'); if (ch >= 'A' && ch <= 'F') return (ch - 'A' + 10); if (ch >= 'a' && ch <= 'f') return (ch - 'a' + 10); fprintf(stderr, "illegal file format\n"); Exit(-1); } get_name(str1, str2) register char *str1, *str2; { int count; for (count = 0; count < 8; count++) { if (*str1 == '\n') break; *str2++ = *str1++; } while (count < 8) { *str2++ = '\0'; count++; } } do_header() { int fd; fd = open(o_file, 0); if (read(fd, &header, sizeof(struct exec)) != sizeof(struct exec)) { fprintf(stderr, "%s: no executable file\n", o_file); Exit(-1); } if (BADMAG(header)) { fprintf(stderr, "%s: bad header\n", o_file); Exit(-1); } if (header.a_syms != 0L) { fprintf(stderr, "%s: symbol table is installed\n", o_file); Exit(-1); } fseek(o_fd, A_SYMPOS(header), 0); nr_symbols = 0; close(fd); } redo_header(fd) FILE *fd; { header.a_syms = nr_symbols * sizeof(struct nlist); fseek(fd, 0L, 0); if (fwrite(&header, sizeof(header), 1, fd) != 1) { fprintf(stderr, "%s: can't write\n", o_file); Exit(-1); } } SHAR_EOF fi echo shar: "extracting 'src/cc1.1.c.diff'" '(897 characters)' if test -f 'src/cc1.1.c.diff' then echo shar: "will not over-write existing file 'src/cc1.1.c.diff'" else cat << \SHAR_EOF > 'src/cc1.1.c.diff' 19a20 > #define SYMBOL_FILE "symbol.out" /* symbol table for prof */ 77,81c78,81 < struct arglist LD_TAIL = { < 2, < { < "/usr/lib/libc.a", < "/usr/lib/end.s" --- > struct arglist M_LD_HEAD = { > 1, > { > "/usr/lib/mrtso.s" 84a85,92 > struct arglist LD_TAIL = { > 2, > { > "/usr/lib/libc.a", > "/usr/lib/end.s" > } > }; > 115a124 > int p_flag = 0; /* profil flag */ 207d215 < case 'p': 210a219,222 > case 'p': > p_flag = 1; > append(&ASLD_FLAGS, "-s"); > break; 333a346,347 > register char *f; > 339,342c353,361 < concat(call, &LD_HEAD); < concat(call, &LDFILES); < concat(call, &LD_TAIL); < if (runvec(call, (char *)0)) { --- > if (p_flag) > concat(call, &M_LD_HEAD); > else concat(call, &LD_HEAD); > concat(call, &LDFILES); > concat(call, &LD_TAIL); > if (p_flag) > f = SYMBOL_FILE; > else f = (char *) 0; > if (runvec(call, f)) { SHAR_EOF fi echo shar: "extracting 'src/cc1.2.c.diff'" '(1125 characters)' if test -f 'src/cc1.2.c.diff' then echo shar: "will not over-write existing file 'src/cc1.2.c.diff'" else cat << \SHAR_EOF > 'src/cc1.2.c.diff' 20a21,22 > #define SYMBOL_FILE "symbol.out" /* symbol table for prof */ > 31c33 < !!! AH HA! I HAVE YOUR ATTENTION! --- > /*!!! AH HA! I HAVE YOUR ATTENTION! 44c46 < /* #define MEM512K */ --- > #define MEM512K 70,71c72 < { < "/usr/lib/crtso.s", --- > { "/usr/lib/crtso.s" 75,79c76,78 < struct arglist LD_TAIL = { < 2, < { < "/usr/lib/libc.a", < "/usr/lib/end.s" --- > struct arglist M_LD_HEAD = { > 1, > { "/usr/lib/mrtso.s" 82a82,89 > struct arglist LD_TAIL = { > 2, > { > "/usr/lib/libc.a", > "/usr/lib/end.s" > } > }; > 114a122 > int p_flag = 0; /* profil flag */ 143a152 > register char *f; 202d210 < case 'p': 205a214,217 > case 'p': > p_flag = 1; > append(&ASLD_FLAGS, "-s"); > break; 224d235 < register char *f; 338,341c349,357 < concat(call, &LD_HEAD); < concat(call, &LDFILES); < concat(call, &LD_TAIL); < if (runvec(call, (char *)0)) { --- > if (p_flag) > concat(call, &M_LD_HEAD); > else concat(call, &LD_HEAD); > concat(call, &LDFILES); > concat(call, &LD_TAIL); > if (p_flag) > f = SYMBOL_FILE; > else f = (char *) 0; > if (runvec(call, f)) { SHAR_EOF fi echo shar: "extracting 'src/nm.c'" '(3949 characters)' if test -f 'src/nm.c' then echo shar: "will not over-write existing file 'src/nm.c'" else cat << \SHAR_EOF > 'src/nm.c' /* nm - print name list. Author: Dick van Veen, veench@cs.vu.nl */ #include <a.out.h> #include <stdio.h> /* * Read the name list in memory, sort it, and print it. * */ /* * nm [-gnopru] [file] ... * * flags: * -g print only external symbols. * -n sort numerically rather than alphabetically. * -o prepend file name to each line rather than only once. * -p don't sort, print in symbol-table order. * -r sort in reverse order. * -u print only undefined symbols. * * - when no file name is present, a.out is assumed. * * NOTE: no archives are supported because assembly files don't * have symbol tables. * */ #define A_OUT "a.out" int g_flag; int n_flag; int o_flag; int p_flag; int r_flag; int u_flag; char io_buf[BUFSIZ]; /* io buffer */ struct exec header; /* header of a.out file */ int stbl_elems; /* #elements in symbol table */ main(argc, argv) int argc; char **argv; { argv++; while (*argv != 0 && **argv == '-') { *argv += 1; while (**argv != '\0') { switch (**argv) { case 'g': g_flag = 1; break; case 'n': n_flag = 1; break; case 'o': o_flag = 1; break; case 'p': p_flag = 1; break; case 'r': r_flag = 1; break; case 'u': u_flag = 1; break; default: fprintf(stderr, "illegal flag: -%c\n", **argv); Exit(-1); } *argv += 1; } argv++; } setbuf(stdin, io_buf); if (*argv == 0) nm(A_OUT); else while (*argv != 0) { nm(*argv); argv++; } Exit(0); } Exit(val) int val; { _cleanup(); exit(val); } nm_sort(stbl1, stbl2) struct nlist *stbl1, *stbl2; { int cmp; if (n_flag) { /* sort numerically */ if ((stbl1->n_sclass & N_SECT) < (stbl2->n_sclass & N_SECT)) cmp = -1; else if ((stbl1->n_sclass & N_SECT) > (stbl2->n_sclass & N_SECT)) cmp = 1; else if (stbl1->n_value < stbl2->n_value) cmp = -1; else if (stbl1->n_value > stbl2->n_value) cmp = 1; else cmp = strncmp(stbl1->n_name, stbl2->n_name, 8); } else { cmp = strncmp(stbl1->n_name, stbl2->n_name, 8); if (cmp == 0) { if (stbl1->n_value < stbl2->n_value) cmp = -1; else if (stbl1->n_value > stbl2->n_value) cmp = 1; } } if (r_flag) cmp = -cmp; /* reverse sort */ return(cmp); } nm(file) char *file; { struct nlist *stbl; int fd; fd = open(file, 0); if (fd == -1) { fprintf(stderr, "can't open %s\n", file); return; } if (read_header(fd)) { fprintf(stderr, "%s: no executable file\n", file); return; } stbl = (struct nlist *) malloc((int) (header.a_syms & 0xFFFF)); if (stbl == NULL) { fprintf(stderr, "%s: can't allocate symbol table\n", file); return; } if (read(fd, stbl, (int) (header.a_syms & 0xFFFF)) != (int) (header.a_syms & 0xFFFF)) { fprintf(stderr, "%s: can't read symbol table\n", file); return; } stbl_elems = (int) header.a_syms/sizeof(struct nlist); if (!p_flag) qsort(stbl, stbl_elems, sizeof(struct nlist), nm_sort); nm_print(file, stbl); close(fd); } read_header(fd) int fd; { if (read(fd, &header, sizeof(struct exec)) != sizeof(struct exec)) return(1); if (BADMAG(header)) return(1); lseek(fd, A_SYMPOS(header), 0); return(0); } nm_print(file, stbl) char *file; register struct nlist *stbl; { struct nlist *last; char name[9]; int n_sclass; char type; name[8] = '\0'; if (!o_flag) printf("%s:\n", file); for (last = &stbl[stbl_elems]; stbl != last; stbl++) { if (g_flag && !(stbl->n_sclass & C_EXT)) continue; if (u_flag && stbl->n_sclass & N_SECT != N_UNDF) continue; n_sclass = stbl->n_sclass & N_SECT; if (n_sclass == N_ABS) type = 'a'; else if (n_sclass == N_TEXT) type = 't'; else if (n_sclass == N_DATA) type = 'd'; else if (n_sclass == N_BSS) type = 'b'; else type = 'u'; if (stbl->n_sclass & C_EXT) type += 'A' -'a'; strncpy(name, stbl->n_name, 8); if (o_flag) printf("%s:%04X %c %s\n", file, stbl->n_value, type, name); else printf("%04X %c %s\n", stbl->n_value, type, name); } } SHAR_EOF fi echo shar: "extracting 'src/prof.c'" '(7444 characters)' if test -f 'src/prof.c' then echo shar: "will not over-write existing file 'src/prof.c'" else cat << \SHAR_EOF > 'src/prof.c' /* prof - display profile data. Author: Dick van Veen, veench@cs.vu.nl */ /* * Options: -a print all symbols * -l print symbols by value instead of by percentage * -z print also symbols with zero count * * Note that no graphics are supported. * */ #include <a.out.h> #include <stat.h> #include <stdio.h> #define A_OUT "a.out" #define MON_FILE "mon.out" #define SYMBOL_FILE "symol.out" /* contains symbol table */ #define MIN(a, b) ((a <= b) ? (a):(b)) #define MAX(a, b) ((a >= b) ? (a):(b)) /* MINIX does not have floating point support, so we use in all calculations * the type fixpoint. * Fixpoint is a long with 3 decimals, all references to FIXFACTOR are * therefore only used to keep the decimals in the right place. */ typedef long fixpoint; #define FIXFACTOR 128 #define TOFIXPOINT(val) (((long) val) * FIXFACTOR) /* The mon.out file consists of a header, followed by profheader.nfunc * cnt record, the rest of the mon.out file consists of samples. */ struct profhdr { /* header of mon.out file */ unsigned int lowpc; unsigned int highpc; int nfunc; }; struct cnt { /* structure used for call count */ int *pc; /* of functions */ long ncal; }; struct profhdr profheader; /* contains mon.out header */ unsigned int *mon_buf; /* contains samples */ struct symbol { /* internal symbol representation */ struct nlist nl; fixpoint time; /* time spent in this ''function'' */ long ncall; }; struct symbol *sym_buf; /* contains internal symbol table */ int symbol_cnt; /* # of symbols */ struct exec header; /* contains a.out header */ int samples; /* number of samples */ int a_flag; /* flags to prof */ int l_flag; int z_flag; char *a_out_file, *mon_out_file; /* names of files */ fixpoint total_time; /* count of samples */ char io_buf[BUFSIZ]; /* io buffer */ int sym_cmp(), time_cmp(); unsigned int snr2pc(); extern FILE *fopen(); extern char *calloc(); main(argc, argv) int argc; char **argv; { argv++; if (*argv != 0 && **argv == '-') { *argv += 1; while (**argv != 0) { if (**argv == 'a') a_flag = 1; else if (**argv == 'l') l_flag = 1; else if (**argv == 'z') z_flag = 1; else fprintf(stderr, "illegal flag: -%c\n", **argv); *argv += 1; } argv++; } if (*argv == 0) a_out_file = A_OUT; else { a_out_file = *argv; argv += 1; } if (*argv == 0) mon_out_file = MON_FILE; else mon_out_file = *argv; read_aout(a_out_file); read_monout(mon_out_file); print_samples(); Exit(0); } Exit(val) int val; { _cleanup(); /* may be this gets fixed sometime */ exit(val); } read_aout(file) char *file; { FILE *fd; fd = fopen(file, "r"); setbuf(fd, io_buf); if (fd == NULL) { fprintf(stderr, "can't open %s\n", file); Exit(-1); } if (fread(&header, sizeof(struct exec), 1, fd) != 1) { fprintf(stderr, "%s: can't read header\n", file); Exit(-1); } if (BADMAG(header)) { fprintf(stderr, "%s: no executable file\n", file); Exit(-1); } if (header.a_syms == 0L) { fprintf(stderr, "%s: no symbol table\n", file); Exit(-1); } read_symbols(fd, file, header.a_syms); fclose(fd); } read_symbols(fd, file, size) FILE *fd; char *file; long size; { long length; int count; struct nlist nsymbol; count = 0; length = 0L; fseek(fd, A_SYMPOS(header), 0); while (length < size) { length += sizeof(struct nlist); if (fread(&nsymbol, sizeof(struct nlist), 1, fd) != 1) break; if ((nsymbol.n_sclass & N_SECT) != N_TEXT) continue; if (!a_flag && !(nsymbol.n_sclass & C_EXT)) continue; count++; } if (length != size) { fprintf(stderr, "%s: can't read symbol table\n", file); Exit(-1); } if (count == 0) { fprintf(stderr, "%s: no symbols\n", file); Exit(-1); } sym_buf = (struct symbol *) calloc(count+1, sizeof(struct symbol)); if (sym_buf == NULL) { fprintf(stderr,"can't allocate %d bytest for symbol table\n", (count + 1) * sizeof(struct symbol)); Exit(-1); } fseek(fd, A_SYMPOS(header), 0); symbol_cnt = count; count = 0; while (count < symbol_cnt) { fread(&sym_buf[count].nl, sizeof(struct nlist), 1, fd); if ((sym_buf[count].nl.n_sclass & N_SECT) != N_TEXT) continue; if (!a_flag && !(sym_buf[count].nl.n_sclass & C_EXT)) continue; count++; } qsort(sym_buf, count, sizeof(struct symbol), sym_cmp); } read_monout(mon_out) char *mon_out; { FILE *fd; struct stat buf; long sample_start; fd = fopen(mon_out, "r"); setbuf(fd, io_buf); if (fd == NULL) { fprintf(stderr, "can't open %s\n", mon_out); Exit(-1); } if (fread(&profheader, sizeof(struct profhdr), 1, fd) != 1) { fprintf(stderr, "%s: can't read header\n", mon_out); Exit(-1); } fstat(fileno(fd), &buf); sample_start = sizeof(struct profhdr) + profheader.nfunc * sizeof(struct cnt); samples = (buf.st_size - sample_start) / sizeof(int); read_counts(fd); fseek(fd, sample_start, 0); assign_samples(fd); fclose(fd); } read_counts(fd) int fd; { /* No counting code supported yet. * Cem produces unusable code with the -p option. */ } assign_samples(fd) FILE *fd; { unsigned int sample, i, perc; unsigned int snr, arealow, areahigh; /* interval covered by sample */ fixpoint time; unsigned int ssize; /* sample size */ unsigned scale; long tmp; unsigned int *tmpptr = (unsigned int *) &tmp; total_time = (fixpoint) 0; /* recompute scale factor */ scale = (profheader.highpc - profheader.lowpc); if (scale > samples*sizeof(unsigned int)) { tmpptr[0] = 0; tmpptr[1] = samples*sizeof(unsigned int); tmp = tmp / scale; scale = tmpptr[0]; } else { scale = 0177777; } for(snr = 0; fread(&sample, sizeof(sample), 1, fd) == 1; snr++) { if (sample == 0) continue; arealow = snr2pc(scale, snr); areahigh = snr2pc(scale, snr + 1); ssize = areahigh - arealow + 1; time = TOFIXPOINT(sample); for(i = 0; i < symbol_cnt; i++) { if (sym_buf[i].nl.n_value > areahigh) break; if (sym_buf[i+1].nl.n_value <= arealow) continue; perc = (MIN(areahigh, sym_buf[i+1].nl.n_value) - MAX(arealow, sym_buf[i ].nl.n_value)); if (perc > 0) { sym_buf[i].time += (((perc+1)*time) / ssize); } } total_time += time; } if (total_time == (fixpoint) 0) { fprintf(stderr, "no samples accumulated\n"); Exit(-1); } } unsigned int snr2pc(scale, snr) unsigned int scale, snr; { long tmp; unsigned int *tmpptr = (unsigned int*) &tmp; unsigned pc; tmpptr[0] = 0; tmpptr[1] = snr*sizeof(unsigned); tmp = tmp / scale; return((tmpptr[0] + profheader.lowpc) & ~1); } print_samples() /* Sort the samples according to the flags and print the result. */ { int i; char name[9]; fixpoint time, cumtime; name[8] = '\0'; if (!l_flag) qsort(sym_buf, symbol_cnt, sizeof(struct symbol), time_cmp); printf(" %%time cumsecs name\n"); for (i = 0; i < symbol_cnt; i++) { if (!z_flag && sym_buf[i].time == (fixpoint) 0) continue; strncpy(name, sym_buf[i].nl.n_name, 8); time = ((sym_buf[i].time * 100) * FIXFACTOR) / total_time; cumtime += sym_buf[i].time; printf("%6D.%03D %6D.%03D %8s\n", time / FIXFACTOR, time % FIXFACTOR, (cumtime / 60) / FIXFACTOR, (cumtime / 60) % FIXFACTOR, name); } } int sym_cmp(sym1, sym2) struct symbol *sym1, *sym2; { return(sym1->nl.n_value - sym2->nl.n_value); } int time_cmp(sym1, sym2) struct symbol *sym1, *sym2; { if (sym1->time < sym2->time) return( 1); if (sym1->time > sym2->time) return(-1); return(strncmp(sym1->nl.n_name, sym2->nl.n_name, 8)); } SHAR_EOF fi echo shar: "extracting 'src/strip.c'" '(2921 characters)' if test -f 'src/strip.c' then echo shar: "will not over-write existing file 'src/strip.c'" else cat << \SHAR_EOF > 'src/strip.c' /* strip - remove symbols. Author: Dick van Veen, veench@cs.vu.nl */ #include <a.out.h> #include <stdio.h> #include <stat.h> /* * strip [file] ... * * - when no file is present, a.out is assumed. * */ #define A_OUT "a.out" #define NAME_LENGTH 128 /* max file path name */ char buffer[BUFSIZ]; /* used to copy executable */ char new_file[NAME_LENGTH]; /* contains name of temporary */ struct exec header; main(argc, argv) int argc; char **argv; { argv++; if (*argv == NULL) strip(A_OUT); else while (*argv != NULL) { strip(*argv); argv++; } exit(0); } strip(file) char *file; { int fd, new_fd; struct stat buf; fd = open(file, 0); if (fd == -1) { fprintf(stderr, "can't open %s\n", file); close(fd); return; } if (read_header(fd)) { fprintf(stderr, "%s: not an executable file\n", file); close(fd); return; } if (header.a_syms == 0L) { close(fd); /* no symbol table present */ return; } header.a_syms = 0L; /* remove table size */ fstat(fd, &buf); new_fd = make_tmp(new_file, file); if (new_fd == -1) { fprintf(stderr, "can't create temporary file\n"); close(fd); return; } if (write_header(new_fd)) { fprintf(stderr, "%s: can't write temporary file\n"); unlink(new_file); close(fd); close(new_fd); return; } if (copy_file(fd, new_fd, header.a_text + header.a_data)) { fprintf(stderr, "can't copy %s\n", file); unlink(new_file); close(fd); close(new_fd); return; } close(fd); close(new_fd); if (unlink(file) == -1) { fprintf(stderr, "can't unlink %s\n", file); unlink(new_file); return; } link(new_file, file); unlink(new_file); chmod(file, buf.st_mode); } read_header(fd) int fd; { if (read(fd, &header, A_MINHDR) != A_MINHDR) return(1); if (BADMAG(header)) return(1); if (header.a_hdrlen > sizeof(struct exec)) return(1); lseek(fd, 0L, 0); /* variable size header */ if (read(fd, &header, (int) header.a_hdrlen) != (int) header.a_hdrlen) return(1); return(0); } write_header(fd) int fd; { lseek(fd, 0L, 0); if(write(fd, &header, (int)header.a_hdrlen) != (int)header.a_hdrlen) return(1); return(0); } int make_tmp(new_name, name) char *new_name, *name; { int len; char *nameptr; extern char *rindex(); len = strlen(name); if (len + 1 > NAME_LENGTH) return(-1); strcpy(new_name, name); nameptr = rindex(new_name, '/'); if (nameptr == NULL) nameptr = new_name-1; if (nameptr - new_name + 6 + 1 > NAME_LENGTH) return(-1); strcpy(nameptr+1, "XXXXXX"); mktemp(new_name); return(creat(new_name, 0777)); } copy_file(fd1, fd2, size) int fd1, fd2; long size; { long count; int length; count = 0; while (count < size) { length = (int) (size - count); if (length > sizeof(buffer)) length = sizeof(buffer); length = read(fd1, buffer, length); if (length == 0) break; if (write(fd2, buffer, length) != length) return(1); count += length; } if (count < size) return(1); return(0); } SHAR_EOF fi exit 0 # End of shell archive