|
|
1.1 root 1: /* Copyright (c) 1980 Regents of the University of California */
2:
3: static char sccsid[] = "@(#)pc3.c 1.6 9/9/80";
4:
5: /*
6: * Pc3 is a pass in the Berkeley Pascal compilation
7: * process that is performed just prior to linking Pascal
8: * object files. Its purpose is to enforce the rules of
9: * separate compilation for Berkeley Pascal. Pc3 is called
10: * with the same argument list of object files that is sent to
11: * the loader. These checks are performed by pc3 by examining
12: * the symbol tables of the object files:
13: * (1) All source and included files must be "up-to-date" with
14: * the object files of which they are components.
15: * (2) Each global Pascal symbol (label, constant, type,
16: * variable, procedure, or function name) must be uniquely
17: * declared, i.e. declared in only one included file or
18: * source file.
19: * (3) Each external function (or procedure) may be resolved
20: * at most once in a source file which included the
21: * external declaration of the function.
22: *
23: * The symbol table of each object file is scanned and
24: * each global Pascal symbol is placed in a hashed symbol
25: * table. The Pascal compiler has been modified to emit all
26: * Pascal global symbols to the object file symbol table. The
27: * information stored in the symbol table for each such symbol
28: * is:
29: *
30: * - the name of the symbol;
31: * - a subtype descriptor;
32: * - for file symbols, their last modify time;
33: * - the file which logically contains the declaration of
34: * the symbol (not an include file);
35: * - the file which textually contains the declaration of
36: * the symbol (possibly an include file);
37: * - the line number at which the symbol is declared;
38: * - the file which contains the resolution of the symbol.
39: * - the line number at which the symbol is resolved;
40: *
41: * If a symbol has been previously entered into the symbol
42: * table, a check is made that the current declaration is of
43: * the same type and from the same include file as the previous
44: * one. Except for files and functions and procedures, it is
45: * an error for a symbol declaration to be encountered more
46: * than once, unless the re-declarations come from the same
47: * included file as the original.
48: *
49: * As an include file symbol is encountered in a source
50: * file, the symbol table entry of each symbol declared in that
51: * include file is modified to reflect its new logical
52: * inclusion in the source file. File symbols are also
53: * encountered as an included file ends, signaling the
54: * continuation of the enclosing file.
55: *
56: * Functions and procedures which have been declared
57: * external may be resolved by declarations from source files
58: * which included the external declaration of the function.
59: * Functions and procedures may be resolved at most once across
60: * a set of object files. The loader will complain if a
61: * function is not resolved at least once.
62: */
63:
64: char program[] = "pc";
65:
66: #include <sys/types.h>
67: #include <ar.h>
68: #include <stdio.h>
69: #include <ctype.h>
70: #include <a.out.h>
71: #include <stab.h>
72: #include <pagsiz.h>
73: #include <stat.h>
74: #include "pstab.h"
75: #include "pc3.h"
76:
77: int errors = 0;
78:
79: /*
80: * check each of the argument .o files (or archives of .o files).
81: */
82: main( argc , argv )
83: int argc;
84: char **argv;
85: {
86: struct fileinfo ofile;
87:
88: while ( ++argv , --argc ) {
89: # ifdef DEBUG
90: fprintf( stderr , "[main] *argv = %s\n" , *argv );
91: # endif DEBUG
92: ofile.name = *argv;
93: checkfile( &ofile );
94: }
95: exit( errors );
96: }
97:
98: /*
99: * check the namelist of a file, or all namelists of an archive.
100: */
101: checkfile( ofilep )
102: struct fileinfo *ofilep;
103: {
104: union {
105: char mag_armag[ SARMAG + 1 ];
106: struct exec mag_exec;
107: } mag_un;
108: int red;
109: struct stat filestat;
110:
111: ofilep -> file = fopen( ofilep -> name , "r" );
112: if ( ofilep -> file == NULL ) {
113: error( WARNING , "cannot open: %s" , ofilep -> name );
114: return;
115: }
116: fstat( fileno( ofilep -> file ) , &filestat );
117: ofilep -> modtime = filestat.st_mtime;
118: red = fread( (char *) &mag_un , 1 , sizeof mag_un , ofilep -> file );
119: if ( red != sizeof mag_un ) {
120: error( WARNING , "cannot read header: %s" , ofilep -> name );
121: return;
122: }
123: if ( mag_un.mag_exec.a_magic == OARMAG ) {
124: error( WARNING , "old archive: %s" , ofilep -> name );
125: return;
126: }
127: if ( strncmp( mag_un.mag_armag , ARMAG , SARMAG ) == 0 ) {
128: /* archive, iterate through elements */
129: # ifdef DEBUG
130: fprintf( stderr , "[checkfile] archive %s\n" , ofilep -> name );
131: # endif DEBUG
132: ofilep -> nextoffset = SARMAG;
133: while ( nextelement( ofilep ) ) {
134: checknl( ofilep );
135: }
136: } else if ( N_BADMAG( mag_un.mag_exec ) ) {
137: /* not a file.o */
138: error( WARNING , "bad format: %s" , ofilep -> name );
139: return;
140: } else {
141: /* a file.o */
142: # ifdef DEBUG
143: fprintf( stderr , "[checkfile] .o file %s\n" , ofilep -> name );
144: # endif DEBUG
145: fseek( ofilep -> file , 0L , 0 );
146: ofilep -> nextoffset = filestat.st_size;
147: checknl( ofilep );
148: }
149: fclose( ofilep -> file );
150: }
151:
152: /*
153: * check the namelist of this file for conflicts with
154: * previously entered symbols.
155: */
156: checknl( ofilep )
157: register struct fileinfo *ofilep;
158: {
159:
160: long red;
161: struct exec oexec;
162: off_t symoff;
163: long numsyms;
164: register struct nlist *nlp;
165: register char *stringp;
166: long strsize;
167: long sym;
168:
169: red = fread( (char *) &oexec , 1 , sizeof oexec , ofilep -> file );
170: if ( red != sizeof oexec ) {
171: error( WARNING , "error reading struct exec: %s"
172: , ofilep -> name );
173: return;
174: }
175: if ( N_BADMAG( oexec ) ) {
176: return;
177: }
178: symoff = N_SYMOFF( oexec ) - sizeof oexec;
179: fseek( ofilep -> file , symoff , 1 );
180: numsyms = oexec.a_syms / sizeof ( struct nlist );
181: if ( numsyms == 0 ) {
182: error( WARNING , "no name list: %s" , ofilep -> name );
183: return;
184: }
185: nlp = (struct nlist *) calloc( numsyms , sizeof ( struct nlist ) );
186: if ( nlp == 0 ) {
187: error( FATAL , "no room for %d nlists" , numsyms );
188: }
189: red = fread( ( char * ) nlp , numsyms , sizeof ( struct nlist )
190: , ofilep -> file );
191: if ( ftell( ofilep -> file ) + sizeof ( off_t )
192: >= ofilep -> nextoffset ) {
193: error( WARNING , "no string table (old format .o?)"
194: , ofilep -> name );
195: return;
196: }
197: red = fread( (char *) &strsize , sizeof strsize , 1
198: , ofilep -> file );
199: if ( red != 1 ) {
200: error( WARNING , "no string table (old format .o?)"
201: , ofilep -> name );
202: return;
203: }
204: stringp = ( char * ) malloc( strsize );
205: if ( stringp == 0 ) {
206: error( FATAL , "no room for %d bytes of strings" , strsize );
207: }
208: red = fread( stringp + sizeof strsize
209: , strsize - sizeof ( strsize ) , 1 , ofilep -> file );
210: if ( red != 1 ) {
211: error( WARNING , "error reading string table: %s"
212: , ofilep -> name );
213: }
214: # ifdef DEBUG
215: fprintf( stderr , "[checknl] %s: %d symbols\n"
216: , ofilep -> name , numsyms );
217: # endif DEBUG
218: for ( sym = 0 ; sym < numsyms ; sym++) {
219: if ( nlp[ sym ].n_un.n_strx ) {
220: nlp[ sym ].n_un.n_name = stringp + nlp[ sym ].n_un.n_strx;
221: } else {
222: nlp[ sym ].n_un.n_name = "";
223: }
224: checksymbol( &nlp[ sym ] , ofilep );
225: }
226: if ( nlp ) {
227: free( nlp );
228: }
229: if ( stringp ) {
230: free( stringp );
231: }
232: }
233:
234: /*
235: * check a symbol.
236: * look it up in the hashed symbol table,
237: * entering it if necessary.
238: * this maintains a state of which .p and .i files
239: * it is currently in the midst from the nlist entries
240: * for source and included files.
241: * if we are inside a .p but not a .i, pfilep == ifilep.
242: */
243: checksymbol( nlp , ofilep )
244: struct nlist *nlp;
245: struct fileinfo *ofilep;
246: {
247: static struct symbol *pfilep = NIL;
248: static struct symbol *ifilep = NIL;
249: register struct symbol *symbolp;
250:
251: # ifdef DEBUG
252: if ( pfilep && ifilep ) {
253: fprintf( stderr , "[checksymbol] pfile %s ifile %s\n"
254: , pfilep -> name , ifilep -> name );
255: }
256: fprintf( stderr , "[checksymbol] ->name %s ->n_desc %x (%s)\n"
257: , nlp -> n_un.n_name , nlp -> n_desc
258: , classify( nlp -> n_desc ) );
259: # endif DEBUG
260: if ( nlp -> n_type != N_PC ) {
261: /* don't care about the others */
262: return;
263: }
264: symbolp = entersymbol( nlp -> n_un.n_name );
265: if ( symbolp -> lookup == NEW ) {
266: # ifdef DEBUG
267: fprintf( stderr , "[checksymbol] ->name %s is NEW\n"
268: , symbolp -> name );
269: # endif DEBUG
270: symbolp -> desc = nlp -> n_desc;
271: switch ( symbolp -> desc ) {
272: case N_PGLABEL:
273: case N_PGCONST:
274: case N_PGTYPE:
275: case N_PGVAR:
276: case N_PGFUNC:
277: case N_PGPROC:
278: symbolp -> sym_un.sym_str.rfilep = ifilep;
279: symbolp -> sym_un.sym_str.rline = nlp -> n_value;
280: symbolp -> sym_un.sym_str.fromp = pfilep;
281: symbolp -> sym_un.sym_str.fromi = ifilep;
282: symbolp -> sym_un.sym_str.iline = nlp -> n_value;
283: return;
284: case N_PEFUNC:
285: case N_PEPROC:
286: symbolp -> sym_un.sym_str.rfilep = NIL;
287: symbolp -> sym_un.sym_str.rline = 0;
288: /*
289: * functions can only be declared external
290: * in included files.
291: */
292: if ( pfilep == ifilep ) {
293: error( WARNING
294: , "%s, line %d: %s %s must be declared in included file"
295: , pfilep -> name , nlp -> n_value
296: , classify( symbolp -> desc )
297: , symbolp -> name );
298: }
299: symbolp -> sym_un.sym_str.fromp = pfilep;
300: symbolp -> sym_un.sym_str.fromi = ifilep;
301: symbolp -> sym_un.sym_str.iline = nlp -> n_value;
302: return;
303: case N_PSO:
304: pfilep = symbolp;
305: /* and fall through */
306: case N_PSOL:
307: ifilep = symbolp;
308: symbolp -> sym_un.modtime = mtime( symbolp -> name );
309: if ( symbolp -> sym_un.modtime > ofilep -> modtime ) {
310: error( WARNING , "%s is out of date with %s"
311: , ofilep -> name , symbolp -> name );
312: }
313: return;
314: }
315: } else {
316: # ifdef DEBUG
317: fprintf( stderr , "[checksymbol] ->name %s is OLD\n"
318: , symbolp -> name );
319: # endif DEBUG
320: switch ( symbolp -> desc ) {
321: case N_PSO:
322: /*
323: * finding a file again means you are back
324: * in it after finishing an include file.
325: */
326: pfilep = symbolp;
327: /* and fall through */
328: case N_PSOL:
329: /*
330: * include files can be seen more than once,
331: * but they still have to be timechecked.
332: * (this will complain twice for out of date
333: * include files which include other files.
334: * sigh.)
335: */
336: ifilep = symbolp;
337: if ( symbolp -> sym_un.modtime > ofilep -> modtime ) {
338: error( WARNING , "%s is out of date with %s"
339: , ofilep -> name , symbolp -> name );
340: }
341: return;
342: case N_PEFUNC:
343: case N_PEPROC:
344: /*
345: * we may see any number of external declarations,
346: * but they all have to come
347: * from the same include file.
348: */
349: if ( nlp -> n_desc == N_PEFUNC
350: || nlp -> n_desc == N_PEPROC ) {
351: goto included;
352: }
353: /*
354: * an external function can be resolved by
355: * the resolution of the function
356: * if the resolving file
357: * included the external declaration.
358: */
359: if ( ( symbolp -> desc == N_PEFUNC
360: && nlp -> n_desc != N_PGFUNC )
361: || ( symbolp -> desc == N_PEPROC
362: && nlp -> n_desc != N_PGPROC )
363: || symbolp -> sym_un.sym_str.fromp != pfilep ) {
364: break;
365: }
366: /*
367: * an external function can only be resolved once.
368: */
369: if ( symbolp -> sym_un.sym_str.rfilep != NIL ) {
370: break;
371: }
372: symbolp -> sym_un.sym_str.rfilep = ifilep;
373: symbolp -> sym_un.sym_str.rline = nlp -> n_value;
374: return;
375: case N_PGFUNC:
376: case N_PGPROC:
377: /*
378: * functions may not be seen more than once.
379: * the loader will complain about
380: * `multiply defined', but we can, too.
381: */
382: break;
383: case N_PGLABEL:
384: case N_PGCONST:
385: case N_PGTYPE:
386: case N_PGVAR:
387: /*
388: * labels, constants, types, variables
389: * and external declarations
390: * may be seen as many times as they want,
391: * as long as they come from the same include file.
392: * make it look like they come from this .p file.
393: */
394: included:
395: if ( nlp -> n_desc != symbolp -> desc
396: || symbolp -> sym_un.sym_str.fromi != ifilep ) {
397: break;
398: }
399: symbolp -> sym_un.sym_str.fromp = pfilep;
400: return;
401: }
402: /*
403: * this is the breaks
404: */
405: error( WARNING , "%s, line %d: %s already defined (%s, line %d)."
406: , ifilep -> name , nlp -> n_value , nlp -> n_un.n_name
407: , symbolp -> sym_un.sym_str.rfilep -> name
408: , symbolp -> sym_un.sym_str.rline );
409: }
410: }
411:
412: /*
413: * quadratically hashed symbol table.
414: * things are never deleted from the hash symbol table.
415: * as more hash table is needed,
416: * a new one is alloc'ed and chained to the end.
417: * search is by rehashing within each table,
418: * traversing chains to next table if unsuccessful.
419: */
420: struct symbol *
421: entersymbol( name )
422: char *name;
423: {
424: static struct symboltableinfo *symboltable = NIL;
425: char *enteredname;
426: long hashindex;
427: register struct symboltableinfo *tablep;
428: register struct symbol **herep;
429: register struct symbol **limitp;
430: register long increment;
431:
432: enteredname = enterstring( name );
433: hashindex = SHORT_ABS( ( long ) enteredname ) % SYMBOLPRIME;
434: for ( tablep = symboltable ; /*return*/ ; tablep = tablep -> chain ) {
435: if ( tablep == NIL ) {
436: # ifdef DEBUG
437: fprintf( stderr , "[entersymbol] calloc\n" );
438: # endif DEBUG
439: tablep = ( struct symboltableinfo * )
440: calloc( sizeof ( struct symboltableinfo ) , 1 );
441: if ( tablep == NIL ) {
442: error( FATAL , "ran out of memory (entersymbol)" );
443: }
444: if ( symboltable == NIL ) {
445: symboltable = tablep;
446: }
447: }
448: herep = &( tablep -> entry[ hashindex ] );
449: limitp = &( tablep -> entry[ SYMBOLPRIME ] );
450: increment = 1;
451: do {
452: # ifdef DEBUG
453: fprintf( stderr , "[entersymbol] increment %d\n"
454: , increment );
455: # endif DEBUG
456: if ( *herep == NIL ) {
457: /* empty */
458: if ( tablep -> used > ( ( SYMBOLPRIME / 3 ) * 4 ) ) {
459: /* too full, break for next table */
460: break;
461: }
462: tablep -> used++;
463: *herep = symbolalloc();
464: ( *herep ) -> name = enteredname;
465: ( *herep ) -> lookup = NEW;
466: # ifdef DEBUG
467: fprintf( stderr , "[entersymbol] name %s NEW\n"
468: , enteredname );
469: # endif DEBUG
470: return *herep;
471: }
472: /* a find? */
473: if ( ( *herep ) -> name == enteredname ) {
474: ( *herep ) -> lookup = OLD;
475: # ifdef DEBUG
476: fprintf( stderr , "[entersymbol] name %s OLD\n"
477: , enteredname );
478: # endif DEBUG
479: return *herep;
480: }
481: herep += increment;
482: if ( herep >= limitp ) {
483: herep -= SYMBOLPRIME;
484: }
485: increment += 2;
486: } while ( increment < SYMBOLPRIME );
487: }
488: }
489:
490: /*
491: * allocate a symbol from the dynamically allocated symbol table.
492: */
493: struct symbol *
494: symbolalloc()
495: {
496: static struct symbol *nextsymbol = NIL;
497: static long symbolsleft = 0;
498: struct symbol *newsymbol;
499:
500: if ( symbolsleft <= 0 ) {
501: # ifdef DEBUG
502: fprintf( stderr , "[symbolalloc] malloc\n" );
503: # endif DEBUG
504: nextsymbol = ( struct symbol * ) malloc( SYMBOLALLOC );
505: if ( nextsymbol == 0 ) {
506: error( FATAL , "ran out of memory (symbolalloc)" );
507: }
508: symbolsleft = SYMBOLALLOC / sizeof( struct symbol );
509: }
510: newsymbol = nextsymbol;
511: nextsymbol++;
512: symbolsleft--;
513: return newsymbol;
514: }
515:
516: /*
517: * hash a string based on all of its characters.
518: */
519: long
520: hashstring( string )
521: char *string;
522: {
523: register char *cp;
524: register long value;
525:
526: value = 0;
527: for ( cp = string ; *cp ; cp++ ) {
528: value = ( value * 2 ) + *cp;
529: }
530: return value;
531: }
532:
533: /*
534: * quadratically hashed string table.
535: * things are never deleted from the hash string table.
536: * as more hash table is needed,
537: * a new one is alloc'ed and chained to the end.
538: * search is by rehashing within each table,
539: * traversing chains to next table if unsuccessful.
540: */
541: char *
542: enterstring( string )
543: char *string;
544: {
545: static struct stringtableinfo *stringtable = NIL;
546: long hashindex;
547: register struct stringtableinfo *tablep;
548: register char **herep;
549: register char **limitp;
550: register long increment;
551:
552: hashindex = SHORT_ABS( hashstring( string ) ) % STRINGPRIME;
553: for ( tablep = stringtable ; /*return*/ ; tablep = tablep -> chain ) {
554: if ( tablep == NIL ) {
555: # ifdef DEBUG
556: fprintf( stderr , "[enterstring] calloc\n" );
557: # endif DEBUG
558: tablep = ( struct stringtableinfo * )
559: calloc( sizeof ( struct stringtableinfo ) , 1 );
560: if ( tablep == NIL ) {
561: error( FATAL , "ran out of memory (enterstring)" );
562: }
563: if ( stringtable == NIL ) {
564: stringtable = tablep;
565: }
566: }
567: herep = &( tablep -> entry[ hashindex ] );
568: limitp = &( tablep -> entry[ STRINGPRIME ] );
569: increment = 1;
570: do {
571: # ifdef DEBUG
572: fprintf( stderr , "[enterstring] increment %d\n"
573: , increment );
574: # endif DEBUG
575: if ( *herep == NIL ) {
576: /* empty */
577: if ( tablep -> used > ( ( STRINGPRIME / 3 ) * 4 ) ) {
578: /* too full, break for next table */
579: break;
580: }
581: tablep -> used++;
582: *herep = charalloc( strlen( string ) );
583: strcpy( *herep , string );
584: # ifdef DEBUG
585: fprintf( stderr , "[enterstring] string %s copied\n"
586: , *herep );
587: # endif DEBUG
588: return *herep;
589: }
590: /* quick, check the first chars and then the rest */
591: if ( **herep == *string && strcmp( *herep , string ) == 0 ) {
592: # ifdef DEBUG
593: fprintf( stderr , "[enterstring] string %s found\n"
594: , *herep );
595: # endif DEBUG
596: return *herep;
597: }
598: herep += increment;
599: if ( herep >= limitp ) {
600: herep -= STRINGPRIME;
601: }
602: increment += 2;
603: } while ( increment < STRINGPRIME );
604: }
605: }
606:
607: /*
608: * copy a string to the dynamically allocated character table.
609: */
610: char *
611: charalloc( length )
612: register long length;
613: {
614: static char *nextchar = NIL;
615: static long charsleft = 0;
616: register long lengthplus1 = length + 1;
617: register long askfor;
618: char *newstring;
619:
620: if ( charsleft < lengthplus1 ) {
621: askfor = lengthplus1 > CHARALLOC ? lengthplus1 : CHARALLOC;
622: # ifdef DEBUG
623: fprintf( stderr , "[charalloc] malloc( %d )\n"
624: , askfor );
625: # endif DEBUG
626: nextchar = ( char * ) malloc( askfor );
627: if ( nextchar == 0 ) {
628: error( FATAL , "no room for %d characters" , askfor );
629: }
630: charsleft = askfor;
631: }
632: newstring = nextchar;
633: nextchar += lengthplus1;
634: charsleft -= lengthplus1;
635: return newstring;
636: }
637:
638: /*
639: * read an archive header for the next element
640: * and find the offset of the one after this.
641: */
642: BOOL
643: nextelement( ofilep )
644: struct fileinfo *ofilep;
645: {
646: register char *cp;
647: register long red;
648: register off_t arsize;
649: struct ar_hdr archdr;
650:
651: fseek( ofilep -> file , ofilep -> nextoffset , 0 );
652: red = fread( (char *) &archdr , 1 , sizeof archdr , ofilep -> file );
653: if ( red != sizeof archdr ) {
654: return FALSE;
655: }
656: /* null terminate the blank-padded name */
657: cp = &archdr.ar_name[ ( sizeof archdr.ar_name ) - 1 ];
658: *cp = '\0';
659: while ( *--cp == ' ' ) {
660: *cp = '\0';
661: }
662: /* set up the address of the beginning of next element */
663: arsize = atol( archdr.ar_size );
664: /* archive elements are aligned on 0 mod 2 boundaries */
665: if ( arsize & 1 ) {
666: arsize += 1;
667: }
668: ofilep -> nextoffset = ftell( ofilep -> file ) + arsize;
669: /* say we had one */
670: return TRUE;
671: }
672:
673: /*
674: * variable number of arguments to error, like printf.
675: */
676: error( fatal , message , arg1 , arg2 , arg3 , arg4 , arg5 , arg6 )
677: int fatal;
678: char *message;
679: {
680: fprintf( stderr , "%s: " , program );
681: fprintf( stderr , message , arg1 , arg2 , arg3 , arg4 , arg5 , arg6 );
682: fprintf( stderr , "\n" );
683: if ( fatal == FATAL ) {
684: exit( 2 );
685: }
686: errors = 1;
687: }
688:
689: /*
690: * find the last modify time of a file.
691: * on error, return the current time.
692: */
693: time_t
694: mtime( filename )
695: char *filename;
696: {
697: struct stat filestat;
698:
699: # ifdef DEBUG
700: fprintf( stderr , "[mtime] filename %s\n"
701: , filename );
702: # endif DEBUG
703: if ( stat( filename , &filestat ) != 0 ) {
704: error( WARNING , "%s: cannot open" , filename );
705: return ( (time_t) time( 0 ) );
706: }
707: return filestat.st_mtime;
708: }
709:
710: char *
711: classify( type )
712: unsigned char type;
713: {
714: switch ( type ) {
715: case N_PSO:
716: return "source file";
717: case N_PSOL:
718: return "include file";
719: case N_PGLABEL:
720: return "label";
721: case N_PGCONST:
722: return "constant";
723: case N_PGTYPE:
724: return "type";
725: case N_PGVAR:
726: return "variable";
727: case N_PGFUNC:
728: return "function";
729: case N_PGPROC:
730: return "procedure";
731: case N_PEFUNC:
732: return "external function";
733: case N_PEPROC:
734: return "external procedure";
735: default:
736: return "unknown symbol";
737: }
738: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.