Back to index

lightning-sunbird  0.9+nobinonly
gtscc.c
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 /* */
00038 /*
00039  *--------------------------------------------------------------------------
00040  *
00041  *    
00042  *
00043  *--------------------------------------------------------------------------
00044  *
00045  *    gtscc - Global To Static C/C++ compiler driver.
00046  *
00047  *    Syntax:
00048  *
00049  *    gtscc [options] -c file.cpp ...
00050  *    gtscc [options] file.o ... libxx.a ...
00051  *
00052  *    gtscc is a compiler and linker driver/wrapper for Irix only.
00053  *    gtscc takes all compiler options and passes them onto the Irix
00054  *    cc/CC compiler/linker.
00055  *    Typically, gtscc is used in two phases. Phase one is during compilation.
00056  *    gtscc, the compiler, converts all inline globals to statics, and records
00057  *    the existence of other globals and how to compile the file in the gtscc
00058  *    database file.
00059  *    During linking, globals dependencies are analyzed, and a list of
00060  *    "convertable" globals is determined. Globals that are not referenced
00061  *    globally, but are referenced locally are considered convertable.
00062  *    The linker then recompiles the files that those symbols are in, and
00063  *    converts them to statics. It also calls the archiver to install
00064  *    the converted objects into libraries.
00065  *    Finally the linker is called.
00066  *
00067  *    Created: David Williams, djw@netscape.com, 13-Feb-1997
00068  *
00069  *--------------------------------------------------------------------------
00070  */
00071 #include <stdio.h>
00072 #include <stdlib.h>
00073 #include <string.h>
00074 #include <sys/types.h>
00075 #include <sys/wait.h>
00076 #include <sys/param.h>
00077 #include <sys/types.h>
00078 #include <unistd.h>
00079 #include <ctype.h>
00080 
00081 #if defined(LINUX) && defined(__GLIBC__)
00082 #include <libelf/libelf.h>
00083 #else
00084 #include <libelf.h>
00085 #endif
00086 
00087 #include <sys/stat.h>
00088 #include <fcntl.h>
00089 #include <sys/time.h>
00090 
00091 #define DEFAULT_MAX_GLOBALS 15500
00092 
00093 #define ELFSYM_IS_DEFINED(x)   ((x).st_shndx != SHN_UNDEF)
00094 #define ELFSYM_IS_UNDEFINED(x) ((x).st_shndx == SHN_UNDEF)
00095 
00096 #ifdef IRIX
00097 #define CC_COMMAND  "cc"
00098 #define CCC_COMMAND "CC"
00099 #define AS_COMMAND  "cc"
00100 #define LD_COMMAND  "CC"
00101 #define AR_COMMAND  "ar"
00102 #define AR_OPTIONS  "cr"
00103 #else
00104 #define HANDLES_DASHSO
00105 #define CC_COMMAND  "gcc"
00106 #define CCC_COMMAND "g++"
00107 #define AS_COMMAND  "gcc"
00108 #define LD_COMMAND  "g++"
00109 #define AR_COMMAND  "ar"
00110 #define AR_OPTIONS  "cr"
00111 #endif
00112 
00113 #define EH_NEW(type) (type*)malloc(sizeof(type))
00114 
00115 #define TRUE 1
00116 #define FALSE 0
00117 
00118 #define EH_TAG_FILE   'F'
00119 #define EH_TAG_GLOBAL 'G'
00120 #define EH_TAG_ZAPPED 'Z'
00121 #define EH_TAG_INLINE 'I'
00122 #define EH_TAG_UNDEFINED 'U'
00123 
00124 #define VERBOSITY_USER(x)  ((x) > 0)
00125 #define VERBOSITY_DEBUG(x) ((x) > 1)
00126 #define VERBOSITY_MAJOR(x) ((x) > 2)
00127 
00128 static char eh_unnamed_object[] = "<name not known>";
00129 
00130 typedef struct {
00131        char*    name;       /* archive */
00132 } EhArchive;
00133 
00134 typedef struct {
00135        char*      name;     /* name of C/C++ file, relative to rootdir */
00136        char*      directory;/* must compile in this directory */
00137        char**     cc_args;  /* cc -I ..... */
00138        char*      as_savefile;
00139        time_t     compile_time;
00140        char*      target_object;
00141 } EhSource;
00142 
00143 typedef struct EhObject {
00144        struct EhObject* _recompile; /* used for recompilation link list */
00145        unsigned   _needs_unzap;
00146        char*      name;     /* name of .o */
00147        EhArchive* archive;  /* it is stored in */
00148        EhSource*  source;
00149        char*      pathname;
00150        unsigned   nusers;
00151 } EhObject;
00152 
00153 typedef enum {
00154        EH_SYM_UNDEFINED,
00155        EH_SYM_DEFINED,
00156        EH_SYM_ZAPPED,
00157        EH_SYM_INLINE /* are treated special - they belong to no file */
00158 } EhSymState;
00159 
00160 typedef struct EhSym {
00161        struct EhSym* _next; /* used for link list */
00162        char*      name;     /* name of symbol */
00163        EhObject*  object;   /* if symbol is undefined == NULL */
00164        unsigned   ngusers;   /* number of global users */
00165        unsigned   nlusers;   /* number of local file users */
00166 
00167 #if 0
00168        unsigned   section;  /* section in elf file */
00169        unsigned   index;    /* index into symbol table */
00170        unsigned char info;
00171        unsigned   dirty;
00172 #endif
00173        EhSymState state;
00174 } EhSym;
00175 
00176 #define EHSYM_ISDEFINED(x)   ((x)->object!=NULL && (x)->state==EH_SYM_DEFINED)
00177 #define EHSYM_ISZAPPED(x)    ((x)->object!=NULL && (x)->state==EH_SYM_ZAPPED)
00178 #define EHSYM_ISUNDEFINED(x) ((x)->object == NULL)
00179 #define EHSYM_ISUSED(x)      ((x)->nusers != 0)
00180 #define EHSYM_ISINLINE(x)    ((x)->state == EH_SYM_INLINE)
00181 
00182 #define EH_OBJECT_CANBUILD(x) \
00183 ((x)->source != NULL && (x)->name != eh_unnamed_object)
00184 
00185 #define USE_HASHING
00186 
00187 typedef struct {
00188 #ifdef USE_HASHING
00189        EhSym** heads;
00190        unsigned size;
00191 #else
00192        EhSym* head;
00193 #endif
00194        unsigned nentries;
00195 } EhSymTable;
00196 
00197 static char*
00198 make_relative_pathname(char* buf, char* filename, char* rootdir)
00199 {
00200        char  buf1[MAXPATHLEN];
00201        char  buf2[MAXPATHLEN];
00202        char* p;
00203        char* q;
00204 
00205        if (rootdir == NULL) {
00206               strcpy(buf, filename);
00207               return filename;
00208        }
00209 
00210        if (filename[0] != '/') {
00211               if (getcwd(buf2, sizeof(buf2)) == NULL) {
00212                      fprintf(stderr, "cannot get pwd\n");
00213                      return NULL;
00214               }
00215 
00216               strcat(buf2, "/");
00217               strcat(buf2, filename);
00218 
00219               filename = buf2;
00220        }
00221 
00222        if (realpath(filename, buf1) == NULL) {
00223               fprintf(stderr, "realpath(%s,..) failed\n", filename);
00224               return NULL;
00225        }
00226        
00227        if (realpath(rootdir, buf2) == NULL) {
00228               fprintf(stderr, "realpath(%s,..) failed\n", rootdir);
00229               return NULL;
00230        }
00231 
00232        strcat(buf2, "/");
00233 
00234        for (p = buf1, q = buf2; *p == *q; p++, q++)
00235               ;
00236 
00237        strcpy(buf, p);
00238 
00239        return buf;
00240 }
00241 
00242 static EhArchive*
00243 EhArchiveNew(char* name, char* rootdir)
00244 {
00245        EhArchive* archive = EH_NEW(EhArchive);
00246        char pathbuf[MAXPATHLEN];
00247 
00248        make_relative_pathname(pathbuf, name, rootdir);
00249 
00250        archive->name = strdup(pathbuf);
00251 
00252        return archive;
00253 }
00254 
00255 #if 0
00256 /*
00257  *    This is evil, we should never free anything, because it messes up
00258  *    interning.
00259  */
00260 static void
00261 EhSourceDelete(EhSource* source)
00262 {
00263        unsigned n;
00264        if (source->name != NULL)
00265               free(source->name);
00266        if (source->directory != NULL)
00267               free(source->directory);
00268        if (source->cc_args != NULL) {
00269               for (n = 0; source->cc_args[n] != NULL; n++)
00270                      free(source->cc_args[n]);
00271               free(source->cc_args);
00272        }
00273        if (source->as_savefile != NULL)
00274               free(source->as_savefile);
00275 }
00276 #endif
00277 
00278 static EhSource*
00279 EhSourceNew(char* name, char** cc_args, char* directory)
00280 {
00281        EhSource* source = EH_NEW(EhSource);
00282        unsigned n;
00283        unsigned m;
00284 
00285        source->name = strdup(name);
00286        source->directory = (directory != NULL)? strdup(directory): NULL;
00287        source->as_savefile = NULL;
00288        source->compile_time = 0;
00289        source->target_object = NULL;
00290        source->cc_args = NULL;
00291 
00292        if (cc_args != NULL) {
00293 
00294               for (n = 0; cc_args[n] != NULL; n++)
00295                      ;
00296 
00297               source->cc_args = (char**)malloc(sizeof(char*) * (n+1));
00298 
00299               for (m = 0, n = 0; cc_args[n] != NULL;) {
00300                      if (strcmp(cc_args[n], "-o") == 0 && cc_args[n+1] != NULL) {
00301                             source->target_object = strdup(cc_args[n+1]);
00302                             n += 2;
00303                      } else {
00304                             source->cc_args[m++] =  strdup(cc_args[n++]);
00305                      }
00306               }
00307 
00308               source->cc_args[m] = NULL;
00309        }
00310 
00311        return source;
00312 }
00313 
00314 static EhObject*
00315 EhObjectNewArchiveObject(EhArchive* archive, char* name)
00316 {
00317        EhObject* object = EH_NEW(EhObject);
00318 
00319        if (name == eh_unnamed_object)
00320               object->name = name;
00321        else
00322               object->name = strdup(name);
00323        object->archive = archive;
00324        object->source = NULL;
00325        object->_recompile = NULL;
00326        object->_needs_unzap = 0;
00327        object->pathname = NULL;
00328        object->nusers = 0;
00329 
00330        return object;
00331 }
00332 
00333 static EhObject*
00334 EhObjectNew(char* name, char* rootdir)
00335 {
00336        EhObject* object = EhObjectNewArchiveObject(NULL, name);
00337        char pathname[MAXPATHLEN];
00338 
00339        make_relative_pathname(pathname, name, rootdir);
00340        object->pathname = strdup(pathname);
00341 
00342        return object;
00343 }
00344 
00345 static EhObject*
00346 EhObjectNewFromSource(EhSource* source)
00347 {
00348        EhObject* object = EhObjectNewArchiveObject(NULL, eh_unnamed_object);
00349 
00350        object->source = source;
00351 
00352        return object;
00353 }
00354 
00355 static char*
00356 EhObjectGetFilename(EhObject* object, char* buf)
00357 {
00358        if (object->archive) {
00359               strcpy(buf, object->archive->name);
00360               strcat(buf, ":");
00361               strcat(buf, object->name);
00362               return buf;
00363        } else {
00364               return object->name;
00365        }
00366 }
00367 
00368 static EhSym*
00369 EhSymNewDefined(char* name, EhObject* object)
00370 {
00371        EhSym* sym = EH_NEW(EhSym);
00372 
00373        sym->name = strdup(name);
00374        sym->object = object;
00375        sym->state = EH_SYM_DEFINED;
00376        sym->ngusers = 0;
00377        sym->nlusers = 0;
00378 
00379        return sym;
00380 }
00381 
00382 static EhSym*
00383 EhSymNewInline(char* name)
00384 {
00385        EhSym* sym = EhSymNewDefined(name, NULL);
00386        sym->state = EH_SYM_INLINE;
00387 
00388        return sym;
00389 }
00390 
00391 static EhSym*
00392 EhSymNewUndefined(char* name)
00393 {
00394        EhSym* sym = EhSymNewDefined(name, NULL);
00395        sym->state = EH_SYM_UNDEFINED;
00396 
00397        return sym;
00398 }
00399 
00400 static EhSym*
00401 EhSymNewZapped(char* name, EhObject* object)
00402 {
00403        EhSym* sym = EhSymNewDefined(name, object);
00404        sym->state = EH_SYM_ZAPPED;
00405 
00406        return sym;
00407 }
00408 
00409 static EhSym*
00410 EhSymNewRandomZap(char* name)
00411 {
00412        EhSym* sym = EhSymNewZapped(name, NULL);
00413 
00414        return sym;
00415 }
00416 
00417 EhSymTable*
00418 EhSymTableNew(unsigned p_size)
00419 {
00420        EhSymTable* table = EH_NEW(EhSymTable);
00421 
00422 #ifdef USE_HASHING
00423        unsigned size;
00424        for (size = 0x1; size < (16*1024); size <<= 1) {
00425               if (size >= p_size)
00426                      break;
00427        }
00428        table->size = size;
00429        table->heads = (EhSym**)calloc(size, sizeof(EhSym*));
00430 #else
00431        table->head = NULL;
00432 #endif
00433        table->nentries = 0;
00434 
00435        return table;
00436 }
00437 
00438 EhSym*
00439 EhSymTableInsert(EhSymTable* table, EhSym* sym)
00440 {
00441 #ifdef USE_HASHING
00442        unsigned long hash = elf_hash(sym->name);
00443        unsigned long mask = table->size - 1;
00444        unsigned index = (hash & mask);
00445 
00446        sym->_next = table->heads[index];
00447        table->heads[index] = sym;
00448 #else
00449        sym->_next = table->head;
00450        table->head = sym;
00451 #endif
00452        table->nentries++;
00453 
00454        return sym;
00455 }
00456 
00457 EhSym*
00458 EhSymTableFind(EhSymTable* table, char* name)
00459 {
00460        EhSym* sym;
00461        EhSym* head;
00462 
00463 #ifdef USE_HASHING
00464        unsigned long hash = elf_hash(name);
00465        unsigned long mask = table->size - 1;
00466        unsigned index = (hash & mask);
00467        head = table->heads[index];
00468 #else
00469        head = table->head;
00470 #endif
00471 
00472        for (sym = head; sym != NULL; sym = sym->_next) {
00473               if (strcmp(name, sym->name) == 0)
00474                      break;
00475        }
00476 
00477        return sym;
00478 }
00479 
00480 typedef int (*eh_dump_mappee_t)(EhSym* sym, void* arg);
00481 
00482 static int
00483 EhSymTableMap(EhSymTable* table, eh_dump_mappee_t func, void* arg)
00484 {
00485        EhSym* sym;
00486        EhSym* head;
00487 
00488 #ifdef USE_HASHING
00489        unsigned n;
00490        for (n = 0; n < table->size; n++) {
00491               head = table->heads[n];
00492 #else
00493               head = table->head; {
00494 #endif
00495               for (sym = head; sym != NULL; sym = sym->_next) {
00496                      if ((func)(sym, arg) == -1)
00497                             return -1;
00498               }
00499        }
00500 
00501        return 0;
00502 }
00503 
00504 typedef struct {
00505        EhObject* o_old;
00506        EhObject* o_new;
00507 } fixup_info;
00508 
00509 static int
00510 fixup_mappee(EhSym* sym, void* arg)
00511 {
00512        fixup_info* info = (fixup_info*)arg;
00513 
00514        if (sym->object == info->o_old)
00515               sym->object = info->o_new;
00516 
00517        return 0;
00518 }
00519 
00520 static EhObject*
00521 EhSymTableObjectFixup(EhSymTable* table, EhObject* o_old, EhObject* o_new)
00522 {
00523        fixup_info info;
00524 
00525        /*
00526         *    Now visit every sym that pointed to tmp, and point it
00527         *    at object.
00528         */
00529        info.o_old = o_old;
00530        info.o_new = o_new;
00531        EhSymTableMap(table, fixup_mappee, &info);
00532        
00533        return o_new;
00534 }
00535 
00536 
00537 
00538 static char*
00539 safe_fgets(char* buf, unsigned size, FILE* fp)
00540 {
00541        unsigned nread = 0;
00542 
00543        if (buf == NULL)
00544               buf = (char*)malloc(size);
00545 
00546        for (;;) {
00547 
00548               if (fgets(&buf[nread], size - nread, fp) == NULL) {
00549                      free(buf);
00550                      return NULL;
00551               }
00552 
00553               if (strchr(buf, '\n') != NULL)
00554                      return buf;
00555 
00556               /*
00557                *    fgets returns n-1 characters and \0
00558                */
00559               nread += (size - nread) - 1;
00560               size += 1024;
00561               buf = (char*)realloc(buf, size);
00562        }
00563 }
00564 
00565 static int
00566 EhSymTableSetSymbolState(EhSymTable* table, char* name, EhSymState new_state)
00567 {
00568        EhSym* sym = EhSymTableFind(table, name);
00569 
00570        if (sym == NULL) {
00571               sym = EhSymNewDefined(name, NULL);
00572 
00573               EhSymTableInsert(table, sym);
00574        }
00575 
00576        /* new_state must be EH_SYM_DEFINED || EH_SYM_ZAPPED */
00577        if (sym->state == EH_SYM_DEFINED || sym->state == EH_SYM_ZAPPED) {
00578               sym->state = new_state;
00579        } else if (sym->state == EH_SYM_INLINE) {
00580               char* state_name;
00581               if (new_state == EH_SYM_DEFINED)
00582                      state_name = "global";
00583               else
00584                      state_name = "static";
00585               fprintf(stderr,
00586                             "WARNING: Symbol %s is an inline.\n"
00587                             "         Forcing the symbol %s will be ignored.\n",
00588                             name,
00589                             state_name);
00590        } else { /* EH_SYM_UNDEFINED */
00591               /*
00592                *    This call is being made after objects have started being
00593                *    read. This is too late. I'm not sure I care though.
00594                */
00595               return -1;
00596        }
00597 
00598        return 0;
00599 }
00600 
00601 static int
00602 EhSymTableFpLoad(EhSymTable* table, FILE* fp)
00603 {
00604        char* buf = NULL; /* I hope this is big enough */
00605        char* p;
00606        char* name;
00607        char* state;
00608        EhSym* sym;
00609        EhSource* source = NULL;
00610        EhObject* object = NULL;
00611        char* cc_args[512];
00612        unsigned n;
00613        unsigned line_n = 0;
00614        char* ctime = NULL;
00615        char* directory;
00616        char* savefile;
00617 
00618        while ((buf = safe_fgets(buf, 1024, fp)) != NULL) {
00619 
00620               if ((p = strchr(buf, '\n')) == NULL) {
00621                      fprintf(stderr, "line to long: %d\n", line_n);
00622                      return -1;
00623               }
00624               *p = '\0';
00625 
00626               line_n++;
00627 
00628               if (buf[0] == '!') /* comment */
00629                      continue;
00630 
00631               for (p = buf; isspace(*p); p++)
00632                      ;
00633 
00634               name = p;
00635               for (; !isspace(*p); p++)
00636                      ;
00637               *p++ = '\0';
00638 
00639               if (name[0] == '\0')
00640                      continue;
00641               
00642               for (; isspace(*p); p++)
00643                      ;
00644 
00645               state = p;
00646               for (; !isspace(*p) && *p != '\0'; p++)
00647                      ;
00648               *p++ = '\0';
00649 
00650               if (state[0] == EH_TAG_GLOBAL
00651                      ||
00652                      state[0] == EH_TAG_ZAPPED
00653                      ||
00654                      state[0] == EH_TAG_INLINE) {
00655                      sym = EhSymTableFind(table, name);
00656                      if (sym == NULL) { /* install a new one */
00657                             
00658                             if (source == NULL && state[0] != EH_TAG_INLINE) {
00659                                    fprintf(stderr,
00660                                                  "[%d] found new style symbol (%s) but no source\n",
00661                                                  line_n, name);
00662                             }
00663 
00664                             if (state[0] == EH_TAG_GLOBAL)
00665                                    sym = EhSymNewDefined(name, object);
00666                             else if (state[0] == EH_TAG_INLINE)
00667                                    sym = EhSymNewInline(name);
00668                             else
00669                                    sym = EhSymNewZapped(name, object);
00670                             
00671                             EhSymTableInsert(table, sym);
00672                      } else {
00673                             if (state[0] == EH_TAG_GLOBAL) {
00674                                    if (sym->state != EH_SYM_DEFINED) {
00675                                           fprintf(stderr,
00676                                                         "out of sync defined symbol: %s, fixing\n",
00677                                                         sym->name);
00678                                           sym->state = EH_SYM_DEFINED;
00679                                    }
00680                             } else if (state[0] == EH_TAG_INLINE) {
00681                                    if (sym->state != EH_SYM_INLINE) {
00682                                           fprintf(stderr,
00683                                                         "out of sync inlined symbol: %s, fixing\n",
00684                                                         sym->name);
00685                                           sym->state = EH_SYM_INLINE;
00686                                    }
00687                             } else {
00688                                    if (sym->state != EH_SYM_ZAPPED) {
00689                                           fprintf(stderr,
00690                                                         "out of sync zapped symbol: %s, fixing\n",
00691                                                         sym->name);
00692                                           sym->state = EH_SYM_ZAPPED;
00693                                    }
00694                             }
00695 
00696 #if 0
00697                             /* these are probably "special" symbols like .div */
00698                             if (sym->object != object) {
00699                                    fprintf(stderr,
00700                                                  "out of sync object for symbol: %s, ignoring\n",
00701                                                  sym->name);
00702                             }
00703 #endif
00704                      }
00705 
00706                      continue; /* no more fields we care about */
00707               } else if (state[0] == EH_TAG_FILE) {
00708 
00709                      directory = p;
00710                      for (; !isspace(*p) && *p != '\0'; p++)
00711                             ;
00712                      *p++ = '\0';
00713 
00714                      savefile = p;
00715                      for (; !isspace(*p) && *p != '\0'; p++)
00716                             ;
00717                      *p++ = '\0';
00718 
00719                      ctime = p;
00720                      for (; !isspace(*p) && *p != '\0'; p++)
00721                             ;
00722                      *p++ = '\0';
00723 
00724                      for (n = 0; *p != '\0';) {
00725 
00726                             for (; isspace(*p); p++)
00727                                    ;
00728                      
00729                             cc_args[n++] = p++;
00730                             
00731                             for (; !isspace(*p) && *p != '\0'; p++)
00732                                    ;
00733                             
00734                             if (*p == '\0')
00735                                    break;
00736 
00737                             *p++ = '\0';
00738                      }
00739                      cc_args[n] = NULL;
00740 
00741                      if (strcmp(directory, ".") == 0)
00742                             directory = NULL;
00743                      source = EhSourceNew(name, cc_args, directory);
00744                      if (ctime != NULL)
00745                             source->compile_time = (time_t)atoi(ctime);
00746                      object = EhObjectNewFromSource(source);
00747 
00748               } else { /* old style symbol list */
00749                      sym = EhSymTableFind(table, name);
00750                      if (sym != NULL) {
00751                             if (sym->state != EH_SYM_ZAPPED) {
00752                                    fprintf(stderr,
00753                                                  "out of sync random zapped symbol: %s, fixing\n",
00754                                                  sym->name);
00755                                    sym->state = EH_SYM_ZAPPED;
00756                             }
00757                      } else {
00758                             sym = EhSymNewRandomZap(name);
00759                      }
00760               }
00761        }
00762 
00763        return line_n;
00764 }
00765 
00766 typedef struct {
00767        EhSym**  vector;
00768        unsigned index;
00769 } flush_info;
00770 
00771 static int
00772 flush_mappee(EhSym* sym, void* arg)
00773 {
00774        flush_info* info = (flush_info*)arg;
00775 
00776        if (sym->state == EH_SYM_INLINE
00777               ||
00778               (sym->object != NULL && sym->state == EH_SYM_DEFINED)
00779               ||
00780               (sym->object != NULL && sym->state == EH_SYM_ZAPPED)) {
00781               if (info->vector != NULL)
00782                      info->vector[info->index] = sym;
00783               info->index++;
00784        }
00785 
00786        return 0;
00787 }
00788 
00789 static  int
00790 flush_compare(const void* ap, const void* bp)
00791 {
00792        EhSym** ax = (EhSym**)ap;
00793        EhSym** bx = (EhSym**)bp;
00794        EhSym* a = *ax;
00795        EhSym* b = *bx;
00796        EhObject* oa = a->object;
00797        EhObject* ob = b->object;
00798        int foo;
00799 
00800        if (oa == NULL && ob != NULL)
00801               return -1;
00802        if (oa != NULL && ob == NULL)
00803               return 1;
00804        if (oa == NULL && ob == NULL) {
00805               foo = strcmp(a->name, b->name);
00806               if (foo < 0)
00807                      return -1;
00808               else if (foo > 0)
00809                      return 1;
00810               return 0;
00811        }
00812 
00813        if (oa->source == NULL && ob->source != NULL)
00814               return -1;
00815        if (oa->source != NULL && ob->source == NULL)
00816               return 1;
00817        if (oa->source == ob->source)
00818               return 0;
00819        if (oa->source < ob->source)
00820               return -1;
00821        if (oa->source > ob->source)
00822               return 1;
00823        foo = strcmp(a->name, b->name);
00824        if (foo < 0)
00825               return -1;
00826        else if (foo > 0)
00827               return 1;
00828        return 0;
00829 }
00830 
00831 static void
00832 EhSourceFpWrite(EhSource* source, FILE* fp)
00833 {
00834        unsigned n = 0;
00835 
00836        fputs(source->name, fp);
00837        fputc(' ', fp);
00838        fputc(EH_TAG_FILE, fp);
00839 
00840        fputc(' ', fp);
00841        if (source->directory != NULL)
00842               fprintf(fp, "%s", source->directory);
00843        else
00844               fputc('.', fp);
00845        
00846        fputc(' ', fp);
00847        if (source->as_savefile != NULL)
00848               fprintf(fp, "%s", source->as_savefile);
00849        else
00850               fputc('.', fp);
00851        
00852        fputc(' ', fp);
00853        fprintf(fp, "%d", source->compile_time);
00854 
00855        if (source->target_object != NULL) {
00856               fputs(" -o ", fp);
00857               fputs(source->target_object, fp);
00858        }
00859        
00860        if (source->cc_args != NULL) {
00861               for (n = 0; source->cc_args[n] != NULL; n++) {
00862                      fputc(' ', fp);
00863                      fputs(source->cc_args[n], fp);
00864               }
00865        }
00866 
00867        if (n < 1)
00868               fprintf(stderr, "WARNING: %s has no args\n", source->name);
00869 
00870        fputc('\n', fp);
00871 }
00872 
00873 static int
00874 EhSymTableFpDump(EhSymTable* table, FILE* fp)
00875 {
00876        flush_info info;
00877        unsigned n;
00878        EhObject* object = NULL;
00879        EhSym**   syms;
00880        EhSym*    sym;
00881        unsigned size;
00882 
00883        info.index = 0;
00884        info.vector = NULL;
00885        EhSymTableMap(table, flush_mappee, (void*)&info);
00886        size = info.index;
00887 
00888        syms = (EhSym**)malloc(sizeof(EhSym*) * size);
00889        info.index = 0;
00890        info.vector = syms;
00891        EhSymTableMap(table, flush_mappee, (void*)&info);
00892 
00893        /* sort */
00894        qsort(syms, size, sizeof(EhSym*), flush_compare);
00895 
00896        /* dump */
00897        for (n = 0; n < size; n++) {
00898               sym = syms[n];
00899 
00900               if (sym->object != object) {
00901                      object = sym->object;
00902 
00903                      if (object->source != NULL) {
00904                             EhSourceFpWrite(object->source, fp);
00905                      }
00906               }
00907 
00908               if (sym->state == EH_SYM_INLINE) {
00909                      fprintf(fp, "%s %c\n", sym->name, EH_TAG_INLINE);
00910               } else if (object->source != NULL && sym->state == EH_SYM_ZAPPED) {
00911                      fprintf(fp, "%s %c\n", sym->name, EH_TAG_ZAPPED);
00912               } else if (object->source != NULL && sym->state == EH_SYM_DEFINED) {
00913                      fprintf(fp, "%s %c\n", sym->name, EH_TAG_GLOBAL);
00914               }
00915        }
00916 
00917        free(syms);
00918 
00919        return n;
00920 }
00921 
00922 int djw_debug;
00923 char* djw_test_name;
00924 
00925 int
00926 eh_process_object(Elf* elf, EhObject* object, EhSymTable* table)
00927 {
00928        Elf32_Shdr *   shdr;
00929        Elf32_Ehdr *   ehdr;
00930        Elf_Scn * scn;
00931        Elf_Data *     shstr_data;
00932        Elf_Data*      sym_data = NULL;
00933        Elf_Data*      str_data = NULL;
00934        Elf_Data*      rel_data[4];
00935        int            nrel_data = 0;
00936        Elf32_Rel*     rel_entries;
00937        Elf_Data*      rela_data[10];
00938        int            nrela_data = 0;
00939        Elf32_Rela*    rela_entries;
00940        unsigned int   cnt;
00941        Elf32_Sym* elf_sym;
00942        int i;
00943        int j;
00944        int k;
00945        char*  name;
00946        EhSym* sym;
00947        char buf[MAXPATHLEN];
00948 
00949        /* Obtain the .shstrtab data buffer */
00950        if (((ehdr = elf32_getehdr(elf)) == NULL) ||
00951               ((scn = elf_getscn(elf, ehdr->e_shstrndx)) == NULL) ||
00952               ((shstr_data = elf_getdata(scn, NULL)) == NULL)) {
00953               fprintf(stderr, "problems on %s\n", EhObjectGetFilename(object, buf));
00954               return -1;
00955        }
00956 
00957        /* get the string table */
00958        for (cnt = 1, scn = NULL; (scn = elf_nextscn(elf, scn)); cnt++) {
00959               if ((shdr = elf32_getshdr(scn)) == NULL) {
00960                      fprintf(stderr, "problems on %s, section %d\n",
00961                                    EhObjectGetFilename(object, buf), cnt);
00962                      return -1;
00963               }
00964 
00965 #if 0
00966               fprintf(stderr, "%s: section %d type %d name %s\n",
00967                             EhObjectGetFilename(object, buf),
00968                             cnt,
00969                             shdr->sh_type,
00970                             (char*)shstr_data->d_buf + shdr->sh_name);
00971 #endif
00972 
00973               /*
00974                *    Get the string table.
00975                */
00976               if (shdr->sh_type == SHT_STRTAB &&
00977 #ifdef sun
00978                      strcmp((char*)shstr_data->d_buf + shdr->sh_name, ".strtab") == 0 &&
00979 #endif
00980                      cnt != ehdr->e_shstrndx) {
00981                      if (str_data != NULL) {
00982                             fprintf(stderr, "multiple string tables for %s - bailing\n",
00983                                           EhObjectGetFilename(object, buf));
00984                             return -1;
00985                      }
00986                      str_data = elf_getdata(scn, NULL);
00987               } else if (shdr->sh_type == SHT_SYMTAB) { /* look into sym table */
00988                      if (sym_data != NULL) {
00989                             fprintf(stderr, "multiple symbol tables for %s - bailing\n",
00990                                           EhObjectGetFilename(object, buf));
00991                             return -1;
00992                      }
00993                      sym_data = elf_getdata(scn, NULL);
00994               } else if (shdr->sh_type == SHT_REL) { /* look into rel table */
00995                      if (nrel_data >= 4) {
00996                             fprintf(stderr, "too many relocation tables for %s bailing\n",
00997                                           EhObjectGetFilename(object, buf));
00998                             return -1;
00999                      }
01000                      rel_data[nrel_data++] = elf_getdata(scn, NULL);
01001               } else if (shdr->sh_type == SHT_RELA) { /* look into rela table */
01002                      if (nrela_data >= 10) {
01003                             fprintf(stderr, "too many RELA tables for %s bailing\n",
01004                                           EhObjectGetFilename(object, buf));
01005                             return -1;
01006                      }
01007                      rela_data[nrela_data++] = elf_getdata(scn, NULL);
01008               }
01009        }
01010 
01011        if (sym_data == NULL) {
01012               fprintf(stderr, "could not load sym table for %s\n",
01013                             EhObjectGetFilename(object, buf));
01014               return -1;
01015        }
01016 
01017        if (str_data == NULL) {
01018               fprintf(stderr, "could not load string table for %s\n",
01019                             EhObjectGetFilename(object, buf));
01020               return -1;
01021        }
01022 
01023        elf_sym = (Elf32_Sym*)sym_data->d_buf;
01024 
01025        for (i = 0; i < (sym_data->d_size/sizeof(Elf32_Sym)); i++) {
01026 
01027               /*
01028                *    We are only interested in globals.
01029                */
01030               if (ELF32_ST_BIND(elf_sym[i].st_info) != STB_GLOBAL)
01031                      continue;
01032               
01033               name = (char *)str_data->d_buf + elf_sym[i].st_name;
01034               
01035               if (djw_test_name != NULL
01036                      && strcmp(djw_test_name, name) == 0) {
01037                      printf("found %s\n", name);
01038               }
01039               
01040               sym = EhSymTableFind(table, name);
01041               
01042               /*
01043                *    Treat inlines as non-globals
01044                */
01045               if (sym != NULL && sym->state == EH_SYM_INLINE)
01046                      continue;
01047               
01048 #if 0
01049               printf("name = %s value = %d type = %d, info = %d,"
01050                         " other = %d, size = %d\n",
01051                         name,
01052                         elf_sym[i].st_value,
01053                         ELF32_ST_TYPE(elf_sym[i].st_info),
01054                         elf_sym[i].st_info,
01055                         elf_sym[i].st_other,
01056                         elf_sym[i].st_size);
01057 #endif
01058               
01059               /* defined */
01060               if (ELFSYM_IS_DEFINED(elf_sym[i])) {
01061                      
01062                      if (sym != NULL) {
01063                             
01064                             if (sym->object == NULL) { /* object undefined */
01065                                    sym->object = object;
01066                             } else if (sym->object->name==eh_unnamed_object) {
01067                                    
01068                                    if (object->source != NULL
01069                                           &&
01070                                           object->source != sym->object->source) {
01071                                           
01072                                           fprintf(stderr,
01073                                                         "warning: symbol %s defined in more than one source file\n"
01074                                                         "last time: %s\n"
01075                                                         "this time: %s (ignored)\n",
01076                                                         sym->name,
01077                                                         object->source->name,
01078                                                         sym->object->source->name);
01079                                    } else {
01080                                           object->source = sym->object->source;
01081                                           /*
01082                                            *    Do a global: sym->object = object;
01083                                            */
01084                                           EhSymTableObjectFixup(table,
01085                                                                                sym->object, /*old*/
01086                                                                                object); /*new*/
01087                                           
01088                                    }
01089                                    
01090                             } else if (sym->object != object) {
01091                                    fprintf(stderr,
01092                                                  "warning: symbol %s define in multiple object files\n"
01093                                                  "last time: %s\n"
01094                                                  "this time: %s (ignored)\n",
01095                                                  sym->name,
01096                                                  object->name,
01097                                                  sym->object->name);
01098                             }
01099                             
01100                             sym->state = EH_SYM_DEFINED;
01101 
01102                      } else {
01103                             sym = EhSymNewDefined(name, object);
01104                             EhSymTableInsert(table, sym);
01105                      }                           
01106 
01107                for (k = 0; k < nrel_data; k++) {
01108                             int nentries = rel_data[k]->d_size/sizeof(Elf32_Rel);
01109 
01110                             rel_entries = (Elf32_Rel*)rel_data[k]->d_buf;
01111                             
01112                             for (j = 0; j < nentries; j++) {
01113                                    if (ELF32_R_SYM(rel_entries[j].r_info) == i) {
01114                                           /* locally referenced */
01115                                           sym->nlusers++;
01116                                    }
01117                             }
01118                      }
01119                for (k = 0; k < nrela_data; k++) {
01120                             int nentries = rela_data[k]->d_size/sizeof(Elf32_Rela);
01121 
01122                             rela_entries = (Elf32_Rela*)rela_data[k]->d_buf;
01123                             
01124                             for (j = 0; j < nentries; j++) {
01125                                    if (ELF32_R_SYM(rela_entries[j].r_info) == i) {
01126                                           /* locally referenced */
01127                                           sym->nlusers++;
01128                                    }
01129                             }
01130                      }
01131               }  
01132               
01133               /* Undefined. */
01134               else if (ELFSYM_IS_UNDEFINED(elf_sym[i])) {
01135                      
01136                      if (sym == NULL) {
01137                             sym = EhSymNewUndefined(name);
01138                             EhSymTableInsert(table, sym);
01139                      }
01140                      sym->ngusers++;
01141               } else {
01142                      
01143 #if 1
01144                      printf("what is this: "
01145                                "name = %s value = %d type = %d, "
01146                                "info = %d, other = %d, size = %d\n",
01147                                name,
01148                                elf_sym[i].st_value,
01149                                ELF32_ST_TYPE(elf_sym[i].st_info),
01150                                elf_sym[i].st_info,
01151                                elf_sym[i].st_other,
01152                                elf_sym[i].st_size);
01153 #endif
01154                      ;
01155               }/* type ==... */
01156        } /* for each symbol */
01157 
01158        return 0;
01159 }
01160 
01161 int
01162 eh_process_file(char* filename, EhSymTable* table, char* rootdir)
01163 {
01164        Elf* elf;
01165        Elf* arf;
01166        int  fd;
01167        Elf_Cmd cmd;
01168        Elf_Kind e_kind;
01169        EhObject* object;
01170        EhArchive* archive;
01171        Elf_Arhdr* arhdr;
01172        char* name;
01173        int   rv = 0;
01174 
01175        if ((fd = open(filename, O_RDONLY)) == -1) {
01176               fprintf(stderr, "error opening %s\n", filename);
01177               return -1;
01178        }
01179 
01180        elf_version(EV_CURRENT);
01181        if ((arf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
01182               return -1;
01183        }
01184 
01185        e_kind = elf_kind(arf);
01186        if (e_kind == ELF_K_ELF) {
01187               object = EhObjectNew(filename, rootdir);
01188               rv = eh_process_object(arf, object, table);
01189               
01190        } else if (e_kind == ELF_K_AR) {
01191 
01192               archive = EhArchiveNew(filename, rootdir);
01193               cmd = ELF_C_READ;
01194 
01195 #if 0
01196               arsyms = elf_getarsym(arf, &narsyms);
01197 
01198               for (i = 0; i < narsyms && arsyms[i].as_name != NULL; i++) {
01199                      printf("%s - %d\n", arsyms[i].as_name, arsyms[i].as_off);
01200               }
01201 
01202               arhdr = elf_getarhdr(arf);
01203               for (i = 0; arhdr[i].ar_rawname != NULL; i++) {
01204 
01205                      if (arhdr[i].ar_name != NULL)
01206                             printf("%s\n", arhdr[i].ar_name);
01207                      else
01208                             printf("[%s]\n", arhdr[i].ar_rawname);
01209               }
01210 #endif
01211 
01212               rv = 0;
01213 
01214               while ((elf = elf_begin(fd, cmd, arf)) != 0) {
01215 
01216                      e_kind = elf_kind(elf);
01217 
01218                      if (e_kind != ELF_K_ELF)
01219                             continue;
01220 
01221                      arhdr = elf_getarhdr(elf);
01222 
01223                      if (arhdr != NULL) {
01224                             if (arhdr->ar_name != NULL)
01225                                    name = arhdr->ar_name;
01226                             else
01227                                    name = arhdr->ar_rawname;
01228                      } else {
01229                             name = eh_unnamed_object;
01230                      }
01231 
01232                      object = EhObjectNewArchiveObject(archive, name);
01233                      rv = eh_process_object(elf, object, table);
01234 
01235                      if (rv == -1)
01236                             break;
01237 
01238                      cmd = elf_next(elf);
01239                      elf_end(elf);
01240               }
01241        }
01242 
01243        elf_end(arf);
01244 
01245        close(fd);
01246 
01247        return rv;
01248 }
01249 
01250 static int
01251 eh_dump_unused(EhSym* sym, void* arg)
01252 {
01253        char buf[MAXPATHLEN];
01254 
01255        printf(/*"0x%x "*/ "%s %d %d ", /*sym,*/
01256                  sym->name, sym->ngusers, sym->nlusers);
01257 
01258        if (EHSYM_ISINLINE(sym))
01259               printf("%c ", EH_TAG_INLINE);
01260        else if (EHSYM_ISZAPPED(sym))
01261               printf("%c ", EH_TAG_ZAPPED);
01262        else if (EHSYM_ISDEFINED(sym))
01263               printf("%c ", EH_TAG_GLOBAL);
01264        else
01265               printf("%c ", EH_TAG_UNDEFINED);
01266 
01267        if (sym->object != NULL) {
01268               printf("%s ", EhObjectGetFilename(sym->object, buf));
01269               if (sym->object->source != NULL) {
01270                      printf("%s recompilable\n", sym->object->source->name);
01271               } else {
01272                      printf("nosource notrecompilable\n");
01273               }
01274        } else {
01275               printf("noobject nosource notrecompilable\n");
01276        }
01277        
01278        return 0;
01279 }
01280 
01281 static void
01282 print_dump(EhSymTable* table)
01283 {
01284        printf("everything\n");
01285        EhSymTableMap(table, eh_dump_unused, NULL);
01286 }
01287 
01288 typedef struct {
01289        unsigned ndefined;
01290        unsigned nused; /* globally */
01291        unsigned nundefined;
01292        unsigned nzapped;
01293        unsigned nzapped_nowused;
01294        unsigned ninlined;
01295        unsigned nunlinked;
01296        unsigned ndeadcode;
01297 } SummaryInfo;
01298 
01299 static int
01300 eh_summary_mappee(EhSym* sym, void* arg) {
01301        SummaryInfo* info = (SummaryInfo*)arg;
01302 
01303        if (EHSYM_ISDEFINED(sym)) {
01304               if (sym->ngusers != 0)
01305                      info->nused++;
01306               else if (sym->object != NULL && sym->object->nusers == 0)
01307                      info->nunlinked++;
01308               else if (sym->nlusers != 0)
01309                      info->ndefined++;
01310               else
01311                      info->ndeadcode++;
01312                      
01313        } else if (EHSYM_ISZAPPED(sym)) { /* one of ours */
01314               if (sym->ngusers != 0)
01315                      info->nzapped_nowused++;
01316               else
01317                      info->nzapped++;
01318        } else if (EHSYM_ISINLINE(sym)) { /* one of ours */
01319               info->ninlined++;
01320        } else {
01321               info->nundefined++;
01322        }
01323 
01324        return 0;
01325 }
01326 
01327 static void
01328 get_summary(EhSymTable* table, SummaryInfo* info)
01329 {
01330        info->ndefined = 0;
01331        info->nused = 0;
01332        info->nundefined = 0;
01333        info->nzapped = 0;
01334        info->nzapped_nowused = 0;
01335        info->ninlined = 0;
01336        info->nunlinked = 0;
01337        info->ndeadcode = 0;
01338        
01339        EhSymTableMap(table, eh_summary_mappee, info);
01340 } 
01341 
01342 static void
01343 print_summary(EhSymTable* table)
01344 {
01345        SummaryInfo info;
01346 
01347        get_summary(table, &info);
01348        
01349        printf("summary:\n"
01350                  "defined and used:             %d\n"
01351                  "defined but unused globally:  %d\n"
01352                  "total globals in target:      %d\n"
01353                  "--------------------------------\n"
01354                  "global to statics *:          %d\n"
01355                  "global to statics (now used): %d\n"
01356                  "inlined to statics *:         %d\n"
01357                  "defined in unlinked objects:  %d\n"
01358                  "defined but unused (deadcode):%d\n"
01359                  "undefined but used:           %d\n",
01360                  info.nused,
01361                  info.ndefined,
01362                  (info.nused + info.ndefined),
01363                  info.nzapped,
01364                  info.nzapped_nowused,
01365                  info.ninlined,
01366                  info.nunlinked,                    
01367                  info.ndeadcode,                    
01368                  info.nundefined);
01369 }
01370 
01371 typedef struct EhDirMapEntree {
01372        char* dirname;
01373        struct EhDirMapEntree* _next;
01374 } EhDirMapEntree;
01375 
01376 typedef struct EhDirMap {
01377        EhDirMapEntree* head;
01378 } EhDirMap;
01379 
01380 static EhDirMap*
01381 EhDirMapNew(void)
01382 {
01383        EhDirMap* dm = EH_NEW(EhDirMap);
01384        dm->head = NULL;
01385        return dm;
01386 }
01387 
01388 static void
01389 EhDirMapAddDirectory(EhDirMap* map, char* dirname)
01390 {
01391        EhDirMapEntree* entree = EH_NEW(EhDirMapEntree);
01392        EhDirMapEntree* foo;
01393 
01394        entree->dirname = strdup(dirname);
01395        entree->_next = NULL;
01396 
01397        if (map->head == NULL) {
01398               map->head = entree;
01399        } else {
01400               for (foo = map->head; foo->_next != NULL; foo = foo->_next)
01401                      ;
01402 
01403               foo->_next = entree;
01404        }
01405 }
01406 
01407 static char*
01408 EhDirMapGetLibName(EhDirMap* map, char* name, char* libbuf)
01409 {
01410        EhDirMapEntree* foo;
01411        struct stat     buf;
01412 
01413        for (foo = map->head; foo != NULL; foo = foo->_next) {
01414               sprintf(libbuf, "%s/lib%s.a", foo->dirname, name);
01415 
01416               if (stat(libbuf, &buf) != -1)
01417                      return libbuf;
01418        }
01419 
01420        return NULL;
01421 }
01422 
01423 static char*
01424 test_for_global(char* buf)
01425 {
01426 #ifdef IRIX
01427        if (strncmp(buf, "\t.globl\t", 8) == 0)
01428               return &buf[8];
01429 #else
01430        if (strncmp(buf, "\t.global ", 9) == 0)
01431               return &buf[9];
01432 #endif
01433        return NULL;
01434 }
01435 
01436 static char*
01437 test_for_file(char* foo, char* buf)
01438 {
01439 #ifdef IRIX
01440        char* p;
01441        char* q;
01442        if (strncmp(buf, "\t.file\t", 6) == 0) {
01443               for (p = &buf[6]; *p != '"' && *p != '\0'; p++)
01444                      ;
01445               if (*p == '\0')
01446                      return NULL;
01447               p++; /* quote */
01448               q = strchr(p, '"');
01449               if (q == NULL)
01450                      return NULL;
01451               memcpy(foo, p, q - p);
01452               foo[q - p] = '\0';
01453               return foo;
01454        }
01455 #else
01456        printf("test_for_file() not implemented\n");
01457 #endif
01458        return NULL;
01459 }
01460 
01461 static int
01462 EhSourceZapFp(EhSource* source, EhSymTable* table, FILE* fpi, FILE* fpo,
01463                        unsigned verbosity, unsigned cplusplus)
01464 {
01465        char*     buf = NULL;
01466        char*     p;
01467        int       nzap = 0;
01468        char*     name;
01469        EhSym*    sym;
01470        int       i_zapped;
01471        EhObject* object = EhObjectNewFromSource(source);
01472        char*     filename = source->name;
01473        char*     tmp_name;
01474        char      foo[256];
01475        unsigned  line_n = 0;
01476 
01477        if (VERBOSITY_DEBUG(verbosity))
01478               fputs("gts: ", stderr);
01479 
01480        while ((buf = safe_fgets(buf, 4192, fpi)) != NULL) {
01481 
01482               i_zapped = 0;
01483               for (p = buf; *p != '\0' && *p != '\n'; p++)
01484                      ;
01485               *p = '\0';
01486 
01487               if ((tmp_name = test_for_file(foo, buf)) != NULL) {
01488                      if (strcmp(tmp_name, filename) != 0) /* not the same file */
01489                             filename = "non local file";
01490                      else
01491                             filename = source->name;
01492               }
01493 
01494               else if ((name = test_for_global(buf)) != NULL) {
01495 
01496                      sym = EhSymTableFind(table, name);
01497 
01498                      /* an inline, we have to treat specially */
01499                      if ((filename != source->name && cplusplus != 0) /* inline now */
01500                             ||
01501                             (sym != NULL && sym->state == EH_SYM_INLINE)) {/* was inline */
01502 
01503                             if (!sym) { 
01504 
01505                                    sym = EhSymNewInline(name);
01506                                    
01507                                    EhSymTableInsert(table, sym);
01508                             }
01509                             sym->state = EH_SYM_INLINE; /* just make sure */
01510 
01511                             if (fpo != NULL) /* always zap inlines we see */
01512                                    fputs(" # gts", fpo);
01513 
01514                      } else { /* a real global */
01515 
01516                             if (fpo != NULL && sym != NULL && EHSYM_ISZAPPED(sym)) {
01517                                    if (VERBOSITY_DEBUG(verbosity)) {
01518                                           fprintf(stderr, "%s ", &buf[8]);
01519                                    }
01520                                    nzap++;
01521 
01522                                    if (fpo != NULL)
01523                                           fputs(" # gts", fpo);
01524                             }
01525 
01526                             if (sym != NULL) {
01527                                    if (sym->object == NULL) {
01528                                           sym->object = object;
01529                                    } else if (sym->object != object) {
01530                                           sym->object->source = source;
01531                                           EhSymTableObjectFixup(table, object, sym->object);
01532                                           object = sym->object;
01533                                    }
01534                             } else { /* install a new one */
01535                                    
01536                                    sym = EhSymNewDefined(name, object);
01537                                    
01538                                    EhSymTableInsert(table, sym);
01539                             }
01540 
01541                      }
01542               }
01543 
01544               if (fpo != NULL) {
01545                      fputs(buf, fpo);
01546                      fputc('\n', fpo);
01547               }
01548               line_n++;
01549        }
01550        
01551        if (VERBOSITY_DEBUG(verbosity))
01552               fputc('\n', stderr);
01553 
01554        return nzap;
01555 }
01556 
01557 static void
01558 print_command(char* command, char** args, unsigned verbosity)
01559 {
01560        int i;
01561        FILE* fp = stderr;
01562        if (!VERBOSITY_USER(verbosity))
01563               return;
01564 
01565        fprintf(fp, "%s: ", command);
01566        for (i = 0; args[i]; i++) {
01567               fprintf(fp, "%s ", args[i]);
01568        }
01569        fprintf(fp, "\n");
01570 }
01571 
01572 static int
01573 do_command(char* label, char** args, unsigned verbosity)
01574 {
01575        int status;
01576        pid_t child_pid;
01577        char* file = args[0];
01578 
01579        print_command(label, args, verbosity);
01580 
01581        if ((child_pid = fork()) == -1) {
01582               fprintf(stderr, "could not fork: ");
01583               perror(NULL);
01584               return -1;
01585        }
01586 
01587        if (child_pid == 0) { /* i am the child */
01588               if (execvp(file, args) == -1) {
01589                      fprintf(stderr, "could not exec %s: ", file);
01590                      perror(NULL);
01591                      exit(3);
01592               }
01593               /*NOTREACHED*/
01594        }
01595 
01596        if (waitpid(child_pid, &status, 0) == -1) {
01597               fprintf(stderr, "wait on %s failed: ", file);
01598               perror(NULL);
01599               return -1;
01600        }
01601 
01602        return WEXITSTATUS(status);
01603 }
01604 
01605 static char*
01606 suffix_name(char* s)
01607 {
01608        char* p;
01609 
01610        if ((p = strrchr(s, '.')) != NULL)
01611               return p;
01612        else
01613               return "";
01614 }
01615 
01616 static char base_name_buf[MAXPATHLEN];
01617 
01618 static char*
01619 base_name(char* s)
01620 {
01621        char* p;
01622 
01623        if ((p = strrchr(s, '.')) != NULL) {
01624               memcpy(base_name_buf, s, p - s);
01625               base_name_buf[p - s] = '\0';
01626               s = base_name_buf;
01627        }
01628        return s;
01629 }
01630 
01631 static char*
01632 file_base_name(char *s)
01633 {
01634        char* p;
01635 
01636        s = base_name(s);
01637 
01638        if ((p = strrchr(s, '/')) != NULL)
01639               s = &p[1];
01640        
01641        return s;
01642 }
01643 static int
01644 EhSourceCompile(EhSource*   source,
01645                             EhSymTable* table,
01646                             unsigned    verbosity,
01647                             unsigned    do_compile,
01648                             unsigned    do_zap,
01649                             unsigned    do_assem)
01650 {
01651        char* filename = source->name;
01652        char** opts = source->cc_args;
01653        char asname[MAXPATHLEN];
01654        char o_asname[MAXPATHLEN];
01655        char* cc_opts[256];
01656        unsigned i = 0;
01657        unsigned j = 0;
01658        FILE* in_fp;
01659        FILE* out_fp;
01660        int   status;
01661        int nzap = 0;
01662        char* save_prefix = NULL;
01663        unsigned do_dash_s = (do_zap != 0 || save_prefix != NULL);
01664        char* cc_command;
01665        char* use_savefile = NULL;
01666        struct timeval start_time;
01667        struct timeval end_time;
01668 #ifdef DEBUG_djw
01669        char savebuf[1024];
01670 #endif
01671        unsigned is_cplusplus = 0;
01672 
01673 #ifdef LINUX
01674        gettimeofday(&start_time,NULL);
01675 #else
01676        gettimeofday(&start_time);
01677 #endif
01678 
01679        /* munge file */
01680 #ifdef HANDLES_DASHSO
01681        if (source->target_object != NULL)
01682               strcpy(asname, base_name(source->target_object));
01683        else
01684 #endif
01685               strcpy(asname, file_base_name(filename));
01686        strcat(asname, ".s");
01687 
01688        strcpy(o_asname, asname);
01689        strcat(o_asname, ".gts_tmp");
01690 
01691        if (strcmp(suffix_name(filename), ".cpp") == 0) {
01692               cc_command = CCC_COMMAND;
01693               is_cplusplus = 1;
01694        } else if (strcmp(suffix_name(filename), ".s") == 0) {
01695               do_compile = FALSE;
01696               cc_command = CC_COMMAND;
01697        } else {
01698               cc_command = CC_COMMAND;
01699        }
01700 
01701        if (do_compile) {
01702 
01703               j = 0;
01704               cc_opts[j++] = cc_command;
01705               cc_opts[j++] = "-c";
01706 
01707               if (do_dash_s) {
01708                      cc_opts[j++] = "-S";
01709 #ifdef HANDLES_DASHSO
01710                      if (source->target_object != NULL) {
01711                             cc_opts[j++] = "-o";
01712                             cc_opts[j++] = asname;
01713                      }
01714 #endif
01715               } else if (source->target_object != NULL) {
01716                      cc_opts[j++] = "-o";
01717                      cc_opts[j++] = source->target_object;
01718               }
01719               
01720               i = 0;
01721               while (opts[i] != NULL)
01722                      cc_opts[j++] = opts[i++];
01723               
01724               cc_opts[j++] = filename;
01725               cc_opts[j] = NULL;
01726               
01727               if ((status = do_command("compile", cc_opts, verbosity)) != 0) {
01728                      fprintf(stderr, "compile failed (returned %d)\n", status);
01729                      return -1;
01730               }
01731 
01732               if (!do_dash_s)
01733                      return 0;
01734        }
01735 
01736        /*
01737         *    Now we have a foo.s file, what do we do with it?
01738         */
01739        if (do_zap > 1) {
01740 
01741               if (use_savefile == NULL)
01742                      use_savefile = asname;
01743 
01744               if ((in_fp = fopen(use_savefile, "r")) == NULL) {
01745                      fprintf(stderr, "could not open %s for reading\n", asname);
01746                      return -1;
01747               }
01748        
01749               if ((out_fp = fopen(o_asname, "w")) == NULL) {
01750                      fprintf(stderr, "could not open %s for writing\n", o_asname);
01751                      return -1;
01752               }
01753        
01754               j = 0;
01755               cc_opts[j++] = "gts";
01756               cc_opts[j++] = asname;
01757               cc_opts[j++] = o_asname;
01758               cc_opts[j++] = NULL;
01759               print_command("gts", cc_opts, verbosity);
01760 
01761               nzap = EhSourceZapFp(source, table, in_fp, out_fp, verbosity, is_cplusplus);
01762 
01763               fclose(in_fp);
01764               fclose(out_fp);
01765 
01766               j = 0;
01767               cc_opts[j++] = "rename";
01768               cc_opts[j++] = o_asname;
01769               cc_opts[j++] = asname;
01770               cc_opts[j++] = NULL;
01771               print_command("rename", cc_opts, verbosity);
01772 
01773 #ifdef DEBUG_djw
01774               strcpy(savebuf, "gts_pre_");
01775               strcat(savebuf, asname);
01776               rename(asname, savebuf);
01777 #endif
01778 
01779               if (rename(o_asname, asname) == -1) {
01780                      fprintf(stderr, "could not rename %s\n", o_asname);
01781                      return -1;
01782               }
01783 
01784        } else if (do_zap > 0) { /* audit only */
01785 
01786               if ((in_fp = fopen(asname, "r")) == NULL) {
01787                      fprintf(stderr, "could not open %s for reading\n", asname);
01788                      return -1;
01789               }
01790        
01791               j = 0;
01792               cc_opts[j++] = "audit";
01793               cc_opts[j++] = asname;
01794               cc_opts[j++] = NULL;
01795               print_command("audit", cc_opts, verbosity);
01796 
01797               nzap = EhSourceZapFp(source, table, in_fp, NULL, verbosity, is_cplusplus);
01798 
01799               fclose(in_fp);
01800        }
01801 
01802        if (do_assem) {
01803               i = 0;
01804               j = 0;
01805               cc_opts[j++] = AS_COMMAND;
01806               cc_opts[j++] = "-c";
01807 
01808               if (source->target_object != NULL) {
01809                      cc_opts[j++] = "-o";
01810                      cc_opts[j++] = source->target_object;
01811               }
01812 
01813               while (opts[i] != NULL)
01814                      cc_opts[j++] = opts[i++];
01815 
01816               cc_opts[j++] = asname;
01817               cc_opts[j] = NULL;
01818 
01819               if ((status = do_command("assemble", cc_opts, verbosity)) != 0) {
01820 
01821                      unlink(asname);
01822 
01823                      fprintf(stderr,
01824                             "gtscc of %s failed (exit status = %d), reverting to %s:\n",
01825                                    filename,
01826                                    status,
01827                                    cc_command);
01828                      
01829                      i = 0;
01830                      j = 0;
01831                      cc_opts[j++] = cc_command;
01832                      cc_opts[j++] = "-c";
01833 
01834                      if (source->target_object != NULL) {
01835                             cc_opts[j++] = "-o";
01836                             cc_opts[j++] = source->target_object;
01837                      }
01838 
01839                      for (; opts[i]; i++, j++)
01840                             cc_opts[j] = opts[i];
01841                      
01842                      cc_opts[j++] = filename;
01843                      cc_opts[j] = NULL;
01844                      
01845                      if ((status = do_command("fix-compile", cc_opts, verbosity)) != 0)
01846                             return -1;
01847 
01848                      return 0;
01849               }
01850        }
01851 
01852        if (save_prefix != NULL && save_prefix[0] != '\0') {
01853 
01854               sprintf(o_asname, save_prefix, file_base_name(filename));
01855 
01856               j = 0;
01857               cc_opts[j++] = "rename";
01858               cc_opts[j++] = asname;
01859               cc_opts[j++] = o_asname;
01860               cc_opts[j++] = NULL;
01861               print_command("savefile", cc_opts, verbosity);
01862 
01863               if (rename(asname, o_asname) == -1) {
01864                      fprintf(stderr, "could not rename %s to %s - sorry\n",
01865                                    asname, o_asname);
01866                      return -1;
01867               }
01868 
01869               if (source->as_savefile != NULL)
01870                      free(source->as_savefile);
01871               source->as_savefile = strdup(o_asname);
01872        } else {
01873 
01874               j = 0;
01875               cc_opts[j++] = "unlink";
01876               cc_opts[j++] = asname;
01877               cc_opts[j++] = NULL;
01878               print_command("unlink", cc_opts, verbosity);
01879 
01880 #ifdef DEBUG_djw
01881               strcpy(savebuf, "gts_post_");
01882               strcat(savebuf, asname);
01883               rename(asname, savebuf);
01884 #else
01885               unlink(asname);
01886 #endif
01887        }
01888 
01889 #ifdef LINUX
01890        gettimeofday(&end_time,NULL);
01891 #else
01892        gettimeofday(&end_time);
01893 #endif
01894 
01895        source->compile_time = ((end_time.tv_sec - start_time.tv_sec) * 1000) +
01896                            ((end_time.tv_usec - start_time.tv_usec) / 1000);
01897 
01898        return nzap;
01899 }
01900 
01901 static char target_buf[MAXPATHLEN]; /* this will go away with rel source */
01902 
01903 static char*
01904 EhSourceGetTarget(EhSource* source)
01905 {
01906        if (source->target_object != NULL)
01907               return source->target_object;
01908 
01909        strcpy(target_buf, base_name(source->name));
01910        strcat(target_buf, ".o");
01911 
01912        return target_buf;
01913 }
01914 
01915 static int
01916 EhArchiveUpdate(EhArchive* archive, char* target, char* rootdir,
01917                             unsigned verbosity)
01918 {
01919        char* args[8];
01920        unsigned nargs;
01921        int status;
01922        char pathname[MAXPATHLEN];
01923 
01924        pathname[0] = '\0';
01925        if (rootdir != NULL) {
01926               strcat(pathname, rootdir);
01927               strcat(pathname, "/");
01928        }
01929        strcat(pathname, archive->name);
01930 
01931 #if 0
01932        nargs = 0;
01933        args[nargs++] = AR_COMMAND;
01934        args[nargs++] = "dc";
01935        args[nargs++] = pathname;
01936        args[nargs++] = target;
01937        args[nargs++] = NULL;
01938        
01939        if ((status = do_command("delete from archive", args, verbosity)) != 0) {
01940               fprintf(stderr, "archive: %s delete %s failed (status = %d)\n",
01941                             pathname,
01942                             target);
01943               return -1;
01944        }
01945 #endif
01946 
01947        nargs = 0;
01948        args[nargs++] = AR_COMMAND;
01949        args[nargs++] = AR_OPTIONS;
01950        args[nargs++] = pathname;
01951        args[nargs++] = target;
01952        args[nargs++] = NULL;
01953        
01954        if ((status = do_command("archive", args, verbosity)) != 0) {
01955               fprintf(stderr, "archive: %s <- %s failed (status = %d)\n",
01956                             pathname,
01957                             target);
01958               return -1;
01959        }
01960 
01961        return 0;
01962 }
01963 
01964 static int
01965 EhObjectRebuild(EhObject*   object,
01966                             EhSymTable* table,
01967                             unsigned    verbosity,
01968                             char*       rootdir)
01969 {
01970        EhSource* source = object->source;
01971        char  cwd[MAXPATHLEN];
01972        char  fullpath[MAXPATHLEN];
01973        int   rv = 0;
01974        int   do_chdir = 0;
01975 
01976        if (!source) {
01977               fprintf(stderr,
01978                             "wanted to recompile %s, but I don't how\n",
01979                             object->name);
01980               return -1;
01981        }
01982        
01983 #if 0
01984        if (VERBOSITY_USER(verbosity))
01985 #endif
01986               fprintf(stderr, "recompiling %s\n", source->name);
01987        
01988        /*
01989         *    Check to see if we need to chdir
01990         */
01991        if (source->directory != NULL) {
01992               if (getcwd(cwd, sizeof(cwd)) == NULL) {
01993                      fprintf(stderr, "cannot get pwd: cannot compile\n");
01994                      return -1;
01995               }
01996               
01997               make_relative_pathname(fullpath, cwd, rootdir);
01998               
01999               if (strcmp(fullpath, source->directory) != 0) {
02000                      fullpath[0] = '\0';
02001                      if (rootdir != NULL) {
02002                             strcat(fullpath, rootdir);
02003                             strcat(fullpath, "/");
02004                      }
02005                      strcat(fullpath, source->directory);
02006 
02007                      if (chdir(fullpath) == -1) {
02008                             fprintf(stderr, "cannot chdir - can't compile\n");
02009                             return -1;
02010                      }
02011                      do_chdir++;
02012               }
02013        }
02014 
02015        rv = EhSourceCompile(source,
02016                                            table,
02017                                            verbosity,
02018                                            TRUE,  /* compile  */
02019                                            2,     /* do zap   */
02020                                            TRUE); /* do assem */
02021 
02022        if (do_chdir) {
02023               if (chdir(cwd) == -1) {
02024                      fprintf(stderr, "cannot chdir - this will be very confused\n");
02025                      return -1;
02026               }
02027        }
02028 
02029        if (rv == -1) {
02030               fprintf(stderr, "recompiling %s failed\n",  source->name);
02031               return -1;
02032        }
02033        
02034        /* do archive */
02035        fullpath[0] = '\0';
02036        if (rootdir != NULL) {
02037               strcat(fullpath, rootdir);
02038               strcat(fullpath, "/");
02039        }
02040 
02041        if (source->directory != NULL)
02042               strcat(fullpath, source->directory);
02043 
02044        strcat(fullpath, "/");
02045        strcat(fullpath, EhSourceGetTarget(source));
02046        
02047        if (object->archive != NULL) {
02048               if (EhArchiveUpdate(object->archive, fullpath, rootdir,
02049                                                  verbosity) == -1)
02050                      return -1;
02051        }
02052 
02053        /* do install */
02054 #if 0
02055        if (rv != -1) {
02056        }
02057 #endif
02058 
02059        return rv;
02060 }
02061 
02062 static int
02063 object_nusers_mappee(EhSym* sym, void* arg)
02064 {
02065        if (sym->object != NULL)
02066               sym->object->nusers += sym->ngusers;
02067        return 0;
02068 }
02069 
02070 typedef struct {
02071        EhObject* recompile_list;
02072        unsigned  recompile_count;
02073        unsigned  recompile_wish_count;
02074        unsigned  unzap_count;
02075        unsigned  zap_count;
02076 } RecompileInfo;
02077 
02078 static int
02079 recompile_init_mappee(EhSym* sym, void* arg)
02080 {
02081        RecompileInfo* info = (RecompileInfo*)arg;
02082 
02083        if (EHSYM_ISZAPPED(sym) && sym->ngusers != 0) {
02084               if (EH_OBJECT_CANBUILD(sym->object)) {
02085                      sym->state = EH_SYM_DEFINED;
02086                      if (sym->object->_recompile == NULL) {
02087                             sym->object->_recompile = info->recompile_list;
02088                             info->recompile_list = sym->object;
02089                             info->recompile_count++;
02090                      }
02091                      info->unzap_count++;
02092                      sym->object->_needs_unzap++;
02093               }
02094               info->recompile_wish_count++;
02095        }
02096        else if (EHSYM_ISDEFINED(sym) /* it's defined */
02097                       && sym->ngusers == 0 /* there are no global users */
02098                       && sym->nlusers != 0 /* BUT, ther are local users */
02099                       && sym->object->nusers != 0) { /* object is linked */
02100 
02101               if (EH_OBJECT_CANBUILD(sym->object)) {
02102                      sym->state = EH_SYM_ZAPPED;
02103                      if (sym->object->_recompile == NULL) {
02104                             sym->object->_recompile = info->recompile_list;
02105                             info->recompile_list = sym->object;
02106                             info->recompile_count++;
02107                      }
02108                      info->zap_count++;
02109               }
02110               info->recompile_wish_count++;
02111        }
02112 
02113        return 0;
02114 }
02115 
02116 static char**    recompile_compare_prefs;
02117 static char**    recompile_compare_unprefs;
02118 
02119 static unsigned
02120 match_prefs(char* candidate, char** prefs)
02121 {
02122        unsigned n;
02123 
02124        for (n = 0; prefs[n] != NULL; n++) {
02125               char*    pref = prefs[n];
02126               unsigned len = strlen(pref);
02127               if (strncmp(pref, candidate, len) == 0)
02128                      return n; /* cool */
02129        }
02130        return (unsigned)-1; /* big! */
02131 }
02132 
02133 static  int
02134 recompile_compare(const void* ap, const void* bp)
02135 {
02136        EhObject** ax = (EhObject**)ap;
02137        EhObject** bx = (EhObject**)bp;
02138        EhObject*  obj_a = *ax;
02139        EhObject*  obj_b = *bx;
02140        EhSource*  src_a = obj_a->source;
02141        EhSource*  src_b = obj_b->source;
02142        unsigned   matcha;
02143        unsigned   matchb;
02144        int        foo;
02145 
02146        if (obj_a->_needs_unzap == 0 && obj_b->_needs_unzap != 0)
02147               return -1;
02148        if (obj_a->_needs_unzap != 0 && obj_b->_needs_unzap == 0)
02149               return 1;
02150 
02151        if (src_a == NULL && src_b != NULL)
02152               return 1;
02153        if (src_a != NULL && src_b == NULL)
02154               return -1;
02155        if (src_a == src_b)
02156               return 0;
02157 
02158        if (recompile_compare_unprefs != NULL
02159               && src_a->directory != NULL && src_b->directory != NULL) {
02160 
02161               matcha = match_prefs(src_a->directory, recompile_compare_unprefs);
02162               matchb = match_prefs(src_b->directory, recompile_compare_unprefs);
02163 
02164               if (matcha > matchb) /* greater is good */
02165                      return -1;
02166               if (matcha < matchb)
02167                      return 1;
02168        }
02169 
02170        if (recompile_compare_prefs != NULL
02171               && src_a->directory != NULL && src_b->directory != NULL) {
02172 
02173               matcha = match_prefs(src_a->directory, recompile_compare_prefs);
02174               matchb = match_prefs(src_b->directory, recompile_compare_prefs);
02175 
02176               if (matcha > matchb) /* greater is bad */
02177                      return 1;
02178               if (matcha < matchb)
02179                      return -1;
02180        }
02181 
02182        /* else same directory probably */
02183        foo = strcmp(src_a->name, src_b->name);
02184 
02185        if (foo < 0)
02186               return -1;
02187        if (foo > 0)
02188               return 1;
02189 
02190        return 0;
02191 }
02192 
02193 static int
02194 do_recompilation(EhSymTable* table, char* gts_file, unsigned max_globals,
02195                              char** prefs, char** unprefs,
02196                              char* rootdir, unsigned verbosity)
02197 {
02198        SummaryInfo s_info;
02199        RecompileInfo info;
02200        unsigned    size;
02201        unsigned n;
02202        EhObject* object;
02203        EhObject** recompiles;
02204        unsigned delta;
02205        int rv;
02206        unsigned nzaps;
02207        EhObject dummy; /* just marks the end of the recomp list */
02208        time_t  eta;
02209 
02210        get_summary(table, &s_info);
02211 
02212        if ((s_info.nused + s_info.ndefined) <= max_globals) {
02213               if (VERBOSITY_USER(verbosity))
02214                      fprintf(stderr,
02215                      "number of globals <= requested max, skipping recompilation\n");
02216               return 0;
02217        }
02218 
02219        /* Init recompilation. */
02220        info.recompile_list = &dummy; /* cannot use NULL, because syms test that */
02221        info.recompile_count = 0;
02222        info.recompile_wish_count = 0;
02223        info.unzap_count = 0;
02224        info.zap_count = 0;
02225        EhSymTableMap(table, recompile_init_mappee, (void*)&info);
02226        size = info.recompile_count;
02227 
02228        recompiles = (EhObject**)malloc(sizeof(EhObject*) * size);
02229 
02230        /* install */
02231        n = 0;
02232        for (object = info.recompile_list;
02233                object != &dummy;
02234                object = object->_recompile) {
02235               recompiles[n++] = object;
02236        }
02237 
02238        /* sort */
02239        recompile_compare_prefs = prefs;
02240        recompile_compare_unprefs = unprefs;
02241        qsort(recompiles, size, sizeof(EhObject*), recompile_compare);
02242 
02243        /*
02244         *    sorted !
02245         *    less recompile the first n, n = ndefined - max
02246         */
02247        delta = (s_info.nused + s_info.ndefined) - max_globals;
02248 
02249        if (delta > info.zap_count) {
02250               fprintf(stderr,
02251                             "WARNING: there too many globals (%d/%d fixables).\n"
02252                             "         I don't think I can fix this, but I'll try.\n"
02253                             "         You might get lucky.\n",
02254                             info.zap_count,
02255                             delta);
02256        }
02257 
02258        if (VERBOSITY_USER(verbosity))
02259               fprintf(stderr, "scheduling recompilation targets:\n");
02260 
02261        eta = 0;
02262        for (n = 0; n < size; n++) {
02263               char* cname = "unknown";
02264               object = recompiles[n];
02265               if (object->source != NULL) {
02266                      cname = object->source->name;
02267                      eta += object->source->compile_time;
02268               }
02269               
02270               if (VERBOSITY_DEBUG(verbosity))
02271                      fprintf(stderr, "object %s from source %s\n", object->name, cname);
02272        }
02273 
02274 #if 0
02275        if (VERBOSITY_USER(verbosity))
02276 #endif
02277               fprintf(stderr, "gts-ing %d symbols, eta = %d minutes\n", delta,
02278                             eta/(60*1000));
02279 
02280        if (gts_file != NULL) {
02281               FILE* zap_fp;
02282               if ((zap_fp = fopen(gts_file, "w")) == NULL) {
02283                      perror(0);
02284                      fprintf(stderr,
02285                                    "WARNING: could not open the gtscc db file %s.\n"
02286                                    "         I will continue with the recompilation, but\n"
02287                                    "         if you recompile any of the files I touched\n"
02288                                    "         I'll have to recompile them after you!\n",
02289                                    gts_file);
02290               } else {
02291               
02292                      EhSymTableFpDump(table, zap_fp);
02293                      
02294                      fclose(zap_fp);
02295               }
02296        }
02297 
02298        for (n = 0, nzaps = 0; n < size && nzaps < delta; n++) {
02299 
02300               object = recompiles[n];
02301               rv = EhObjectRebuild(object, table, verbosity, rootdir);
02302 
02303               if (rv == -1)
02304                      return -1;
02305 
02306               nzaps += rv;
02307 
02308               object->_recompile = NULL; /* clean up now */
02309        }
02310 
02311        if (nzaps < delta) {
02312               fprintf(stderr,
02313                             "WARNING: I wanted to gts %d symbols, but only managed\n"
02314                             "         to get %d of them.\n"
02315                             "         Your link may fail with GOT errors.\n",
02316                             delta,
02317                             nzaps);
02318        }
02319        
02320        free(recompiles);
02321 
02322        return n;
02323 }
02324 
02325 typedef struct FileList
02326 {
02327        char*            name;
02328        struct FileList* next;
02329 } FileList;
02330 
02331 static FileList*
02332 fileListFind(FileList* list, char* name)
02333 {
02334        FileList* foo;
02335 
02336        for (foo = list; foo != NULL; foo = foo->next) {
02337               if (strcmp(name, foo->name) == 0)
02338                      return foo;
02339        }
02340        return NULL;
02341 }
02342 
02343 static FileList*
02344 fileListAppend(FileList** list_a, char* name)
02345 {
02346        FileList* list = *list_a;
02347        FileList* foo;
02348        FileList* last;
02349 
02350        for (foo = list, last = NULL; foo != NULL; last = foo, foo = foo->next)
02351               ;
02352 
02353        if (last == NULL) {
02354               foo = EH_NEW(FileList);
02355               foo->next = NULL;
02356               foo->name = strdup(name);
02357               *list_a = foo;
02358        } else {
02359               foo = EH_NEW(FileList);
02360               foo->next = NULL;
02361               foo->name = strdup(name);
02362               last->next = foo;
02363        }
02364 
02365        return *list_a;
02366 }
02367 
02368 #if 0
02369 static FileList* c_list;
02370 #endif
02371 static FileList* o_list;
02372 
02373 #if 0
02374 static char*
02375 EhSourceAdjustPathname(EhSource* source, char* rootdir)
02376 {
02377        char buf[MAXPATHLEN];
02378        char buf2[MAXPATHLEN];
02379        char* p;
02380        char* q;
02381        char* filename = source->name;
02382 
02383        if (getcwd(buf, sizeof(buf)) == NULL) {
02384               fprintf(stderr, "cannot get pwd\n");
02385               return NULL;
02386        }
02387 
02388        strcat(buf, "/");
02389        strcat(buf, filename);
02390 
02391        if (rootdir == NULL) {
02392               filename = buf;
02393        } else {
02394               if (realpath(buf, buf2) == NULL) {
02395                      fprintf(stderr, "realpath() failed: %s\n", buf2);
02396                      return NULL;
02397               }
02398 
02399               if (realpath(rootdir, buf) == NULL) {
02400                      fprintf(stderr, "realpath() failed: %s\n", buf);
02401                      return NULL;
02402               }
02403               strcat(buf, "/"); 
02404               
02405               for (p = buf, q = buf2; *p == *q; p++, q++)
02406                      ;
02407 
02408               filename = q;
02409        }
02410 
02411        free(source->name);
02412        source->name = strdup(filename);
02413 
02414        return source->name;
02415 }
02416 #endif
02417 
02418 static unsigned
02419 katoi(char *buf)
02420 {
02421        unsigned base = 1;
02422        char* s;
02423        
02424        for (s = buf; isdigit(*s); s++)
02425               ;
02426 
02427        if (*s == 'k' || *s == 'K')
02428               base = 1024;
02429 
02430        *s = '\0';
02431 
02432        return base * atoi(buf);
02433 }
02434 
02435 static void
02436 usage(void)
02437 {
02438        fprintf(stderr,
02439                      "Usage:\n"
02440                      "as a compiler:\n"
02441                      "gtscc [gtscc_options] [compiler_options] -c file.c file.cpp ...\n"
02442                      "gtscc_options:\n"
02443                      "-gtsfile <db.gts>       the gts database file (use this)\n"
02444                      "-gtszapsymbol <name>    convert symbol <name>\n"
02445                      "-gtsnozapsymbol <name>  don't convert symbol <name>\n"
02446                      "-gtsrootdir <directory> the root for the tree (use this)\n"
02447                      "-gtsverbose             be more verbose (3 levels)\n"
02448                      "-gtsnozap               don't convert globals to statics\n"
02449                      "-gtsnoupdate            don't update the database file\n"
02450                      "as a linker:\n"
02451                      "gtscc [gtscc_options] [linker_options] file.o ... libxx.a ...\n"
02452                      "gtscc_options:\n"
02453                      "-gtsfile <db.gts>       the gts database file (use this)\n"
02454                      "-gtszapsymbol <name>    convert symbol <name>\n"
02455                      "-gtsnozapsymbol <name>  don't convert symbol <name>\n"
02456                      "-gtsrootdir <directory> the root for the tree (use this)\n"
02457                      "-gtspref <directory>    please recompile these paths first\n"
02458                      "-gtsunpref <directory>  please try to avoid recompiling these\n"
02459                      "-gtsverbose             be more verbose (3 levels)\n"
02460                      "-gtssummary             print a summary of global usage\n"
02461                      "-gtsdump                print a detailed listing of all symbols\n"
02462                      "-gtsmaxglobals <number>[k] maximum globals allowed in target\n"
02463                      "-gtsnorecompile         don't do the normal recompilation\n"
02464                      "-gtsnolink              don't call linker after recompilation\n"
02465                      "-gtsnoupdate            don't update the database file\n"
02466                      "-help                   print this\n"
02467        );
02468 }
02469 
02470 int
02471 main(int argc, char** argv)
02472 {
02473        EhSymTable* table = EhSymTableNew(1000);
02474        EhSym* sym;
02475        FILE* zap_fp;
02476        unsigned n = 0;
02477        unsigned verbosity = 0;
02478        char* arg_buf[256];
02479        unsigned nargs = 0;
02480        EhDirMap*   dmap = EhDirMapNew();
02481        unsigned do_dump = 0;
02482        unsigned do_summary = 0;
02483        unsigned do_link = 1;
02484        unsigned in_link = 1;
02485        unsigned do_audit = 1;
02486        unsigned do_zap = 1;
02487        unsigned do_assem = 1;
02488        unsigned do_recompile = 1;
02489        unsigned do_collect = 1;
02490        char* name;
02491        char* saveprefix = NULL;
02492        char* rootdir = NULL;
02493        int rv;
02494        EhSource* source = NULL;
02495        char* gts_file = NULL;
02496        char* path_prefs[32];
02497        unsigned npath_prefs = 0;
02498        char* path_un_prefs[32];
02499        unsigned npath_un_prefs = 0;
02500        char* suffix;
02501        unsigned max_globals = DEFAULT_MAX_GLOBALS;
02502        FileList* list;
02503 
02504        if (elf_version(EV_CURRENT) == EV_NONE) {
02505               fprintf(stderr, "something losing about your elf lib - sorry!\n");
02506               return 3;
02507               /* library out of date */
02508               /* recover from error */
02509        }
02510 
02511        arg_buf[nargs] = NULL;
02512 
02513        for (n = 1; n < argc; n++) {
02514 
02515               if (strcmp(argv[n], "-help") == 0) {
02516                      usage();
02517                      return 0;
02518               } else if (strcmp(argv[n], "-gtssummary") == 0) {
02519                      do_summary = 1;
02520               } else if (strcmp(argv[n], "-gtsdump") == 0) {
02521                      do_dump = 1;
02522               } else if (strcmp(argv[n], "-gtsnorecompile") == 0) {
02523                      do_recompile = 0;
02524               } else if (strcmp(argv[n], "-gtsnolink") == 0) {
02525                      do_link = 0;
02526               } else if (strcmp(argv[n], "-gtsverbose") == 0) {
02527                      verbosity++;
02528               } else if (strcmp(argv[n], "-gtsnoupdate") == 0) {
02529                      do_collect = 0;
02530               } else if (strcmp(argv[n], "-gtsnoaudit") == 0) {
02531                      do_audit = 0;
02532               } else if (strcmp(argv[n], "-gtsnozap") == 0) {
02533                      do_zap = 0;
02534               } else if (strcmp(argv[n], "-gtsrootdir") == 0) {
02535                      if (argc < n+2) {
02536                             fprintf(stderr,      "-gtsrootdir requires an argument\n");
02537                             usage();
02538                             return 2;
02539                      }
02540                      rootdir = argv[n+1];
02541                      n++;
02542               } else if (strcmp(argv[n], "-gtsdebugsym") == 0) {
02543                      if (argc < n+2) {
02544                             fprintf(stderr,      "-gtsdebugsym requires an argument\n");
02545                             usage();
02546                             return 2;
02547                      }
02548                      djw_test_name = argv[n+1];
02549                      n++;
02550               } else if (strcmp(argv[n], "-gtsmaxglobals") == 0) {
02551                      if (argc < n+2) {
02552                             fprintf(stderr,      "-gtsmaxglobals requires an argument\n");
02553                             usage();
02554                             return 2;
02555                      }
02556                      max_globals = katoi(argv[n+1]);
02557                      n++;
02558 
02559               } else if (strcmp(argv[n], "-gtspref") == 0) {
02560                      if (argc < n+2) {
02561                             fprintf(stderr,      "-gtspref requires an argument\n");
02562                             usage();
02563                             return 2;
02564                      }
02565                      path_prefs[npath_prefs++] = argv[n+1];
02566                      path_prefs[npath_prefs] = NULL;
02567                      n++;
02568 
02569               } else if (strcmp(argv[n], "-gtsunpref") == 0) {
02570                      if (argc < n+2) {
02571                             fprintf(stderr,      "-gtsunpref requires an argument\n");
02572                             usage();
02573                             return 2;
02574                      }
02575                      path_un_prefs[npath_un_prefs++] = argv[n+1];
02576                      path_un_prefs[npath_un_prefs] = NULL;
02577                      n++;
02578 
02579               } else if (strcmp(argv[n], "-gtssaveprefix") == 0) {
02580                      if (argc < n+2) {
02581                             fprintf(stderr,      "-gtssaveprefix requires an argument\n");
02582                             usage();
02583                             return 2;
02584                      }
02585                      saveprefix = argv[n+1];
02586                      n++;
02587 
02588               } else if (strcmp(argv[n], "-gtsfile") == 0) {
02589 
02590                      struct stat sbuf;
02591 
02592                      if (argc < n+2) {
02593                             fprintf(stderr,      "-gtsfile requires an argument\n");
02594                             usage();
02595                             return 2;
02596                      }
02597 
02598                      gts_file = argv[n+1];
02599                             
02600                      if (stat(gts_file, &sbuf) == -1) {
02601                             fprintf(stderr,
02602                                           "warning: %s does not exist, will be created\n",
02603                                           gts_file);
02604                      } else {
02605                             
02606                             if ((zap_fp = fopen(gts_file, "r")) == NULL) {
02607                                    fprintf(stderr,      "you lose cannot open %s\n", gts_file);
02608                                    usage();
02609                                    return 2;
02610                             }
02611 
02612                             if (EhSymTableFpLoad(table, zap_fp) == -1) {
02613                                    fprintf(stderr,
02614                                                  "error: failed reading symbols from gtsfile %s\n",
02615                                                  argv[n+1]);
02616                                    usage();
02617                                    return 2;
02618                             }
02619                             
02620                             fclose(zap_fp);
02621                      }
02622 
02623                      n++;
02624 
02625               } else if (strcmp(argv[n], "-gtszapsymbol") == 0) {
02626                      if (argc < n+2) {
02627                             fprintf(stderr,      "-gtszapsymbol requires an argument\n");
02628                             usage();
02629                             return 2;
02630                      }
02631 
02632                      EhSymTableSetSymbolState(table, argv[n+1], EH_SYM_ZAPPED);
02633                      n++;
02634 
02635               } else if (strcmp(argv[n], "-gtsnozapsymbol") == 0) {
02636                      if (argc < n+2) {
02637                             fprintf(stderr,      "-gtsnozapsymbol requires an argument\n");
02638                             usage();
02639                             return 2;
02640                      }
02641 
02642                      EhSymTableSetSymbolState(table, argv[n+1], EH_SYM_DEFINED);
02643                      n++;
02644 
02645               } else if (strcmp(argv[n], "-gtsname") == 0) {
02646                      if (argc < n+2) {
02647                             fprintf(stderr,      "-gtsname requires an argument\n");
02648                             usage();
02649                             return 2;
02650                      }
02651 
02652                      sym = EhSymTableFind(table, argv[n+1]);
02653                      if (!sym)
02654                             sym = EhSymNewRandomZap(argv[n+1]);
02655                      n++;
02656                      do_audit = 1;
02657 
02658               } else if (strcmp(argv[n], "-c") == 0) { /* do not link */
02659                      in_link = 0;
02660                      do_link = 0;
02661               } else if (strcmp(argv[n], "-S") == 0) { /* do not assem */
02662                      do_assem = 0;
02663               } else if (strcmp(argv[n], "-o") == 0) { /* parse through */
02664                      arg_buf[nargs++] = argv[n++];
02665                      arg_buf[nargs++] = argv[n];
02666                      arg_buf[nargs] = NULL;
02667               } else if (strcmp((suffix = suffix_name(argv[n])), ".cpp") == 0
02668                                ||
02669                                strcmp(suffix, ".c") == 0
02670                                ||
02671                                strcmp(suffix, ".s") == 0) {
02672                      char pathname[MAXPATHLEN];
02673 
02674                      make_relative_pathname(pathname, ".", rootdir);
02675 
02676                      source = EhSourceNew(argv[n], arg_buf, pathname);
02677 
02678                      rv = EhSourceCompile(source,
02679                                                          table,
02680                                                          verbosity,
02681                                                          TRUE, /* compile, .s files ignore anyway */
02682                                                          (do_audit + do_zap),
02683                                                          do_assem);
02684                      if (rv == -1)
02685                             return 1;
02686 
02687 #if 0
02688                      EhSourceAdjustPathname(source, rootdir);
02689 #endif
02690 
02691               } else if (strcmp(suffix, ".o") == 0 || strcmp(suffix, ".a") == 0) {
02692 
02693                      if (fileListFind(o_list, argv[n]) == NULL) {
02694                             fileListAppend(&o_list, argv[n]);
02695                      } else {
02696                             fprintf(stderr,
02697                                           "%s repeated on command line - ignored\n",
02698                                           argv[n]);
02699                      }
02700                      arg_buf[nargs++] = argv[n];
02701                      arg_buf[nargs] = NULL;
02702 
02703               } else if (strncmp(argv[n], "-L", 2) == 0) {
02704                      EhDirMapAddDirectory(dmap, &argv[n][2]);
02705               } else if (strncmp(argv[n], "-l", 2) == 0) {
02706                      char pathbuf[MAXPATHLEN];
02707                      name = EhDirMapGetLibName(dmap, &argv[n][2], pathbuf);
02708                      if (name != NULL) {
02709                             if (fileListFind(o_list, name) == NULL) {
02710                                    fileListAppend(&o_list, name);
02711                             } else {
02712                                    fprintf(stderr,
02713                                                  "%s repeated on command line - ignored\n",
02714                                                  name);
02715                             }
02716                      } else {
02717                             fprintf(stderr, 
02718                                           "unable to resolve library reference %s - ignoring\n",
02719                                           argv[n]);
02720                      }
02721                      arg_buf[nargs++] = argv[n];
02722                      arg_buf[nargs] = NULL;
02723               } else {
02724                      arg_buf[nargs++] = argv[n];
02725                      arg_buf[nargs] = NULL;
02726               }
02727        }
02728 
02729        /*
02730         *    Analyse objects.
02731         */
02732        if (o_list != NULL) {
02733               for (list = o_list; list != NULL; list = list->next) {
02734 
02735                      if (eh_process_file(list->name, table, rootdir)) {
02736                             fprintf(stderr, "oops we died around %s\n", list->name);
02737                             return 1;
02738                      }
02739               }
02740               
02741               /* look for unused objects */
02742               EhSymTableMap(table, object_nusers_mappee, 0);
02743        }
02744 
02745        if (do_summary) {
02746               print_summary(table);
02747        }
02748 
02749        if (do_dump) {
02750               print_dump(table);
02751        }
02752 
02753        if (!in_link && gts_file != NULL) {
02754               FILE* zap_fp;
02755               if ((zap_fp = fopen(gts_file, "w")) == NULL) {
02756                      perror(0);
02757                      usage();
02758                      return 2;
02759               }
02760 
02761               EhSymTableFpDump(table, zap_fp);
02762               fclose(zap_fp);
02763               return 0;
02764        }
02765 
02766        /*
02767         *    Now the fun really starts.
02768         */
02769        if (do_recompile) {
02770               char** pp = NULL;
02771               char** up = NULL;
02772               
02773               if (npath_prefs > 0)
02774                      pp = path_prefs;
02775               
02776               if (npath_un_prefs > 0)
02777                      up = path_un_prefs;
02778 
02779               if (!do_collect)
02780                      gts_file = NULL;
02781               
02782               rv = do_recompilation(table, gts_file, max_globals, pp, up, rootdir,
02783                                                    verbosity);
02784               if (rv == -1)
02785                      return 1;
02786        }
02787 
02788        /*
02789         *    Finally.
02790         */
02791        if (do_link) {
02792 
02793               int status;
02794 
02795               arg_buf[nargs+1] = NULL;
02796               for (n = nargs; n > 0; n--)
02797                      arg_buf[n] = arg_buf[n-1];
02798               arg_buf[0] = LD_COMMAND;
02799               
02800               status = do_command("link", arg_buf, verbosity);
02801 
02802               if (status == -1)
02803                      return 3;
02804               else
02805                      return status;
02806        }
02807        
02808        return 0;
02809 }