00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "config.h"
00025 #include "system.h"
00026 #include "intl.h"
00027 #include "obstack.h"
00028 #include "hashtab.h"
00029 #include "demangle.h"
00030 #include "collect2.h"
00031
00032 #define MAX_ITERATIONS 17
00033
00034
00035 extern int prepends_underscore;
00036
00037 static int tlink_verbose;
00038
00039
00040
00041
00042 typedef struct symbol_hash_entry
00043 {
00044 const char *key;
00045 struct file_hash_entry *file;
00046 int chosen;
00047 int tweaking;
00048 int tweaked;
00049 } symbol;
00050
00051 typedef struct file_hash_entry
00052 {
00053 const char *key;
00054 const char *args;
00055 const char *dir;
00056 const char *main;
00057 int tweaking;
00058 } file;
00059
00060 typedef struct demangled_hash_entry
00061 {
00062 const char *key;
00063 const char *mangled;
00064 } demangled;
00065
00066
00067
00068 static int hash_string_eq PARAMS ((const void *, const void *));
00069 static hashval_t hash_string_hash PARAMS ((const void *));
00070
00071 static int
00072 hash_string_eq (s1_p, s2_p)
00073 const void *s1_p;
00074 const void *s2_p;
00075 {
00076 const char *const *s1 = (const char *const *) s1_p;
00077 const char *s2 = (const char *) s2_p;
00078 return strcmp (*s1, s2) == 0;
00079 }
00080
00081 static hashval_t
00082 hash_string_hash (s_p)
00083 const void *s_p;
00084 {
00085 const char *const *s = (const char *const *) s_p;
00086 return (*htab_hash_string) (*s);
00087 }
00088
00089 static htab_t symbol_table;
00090
00091 static struct symbol_hash_entry * symbol_hash_lookup PARAMS ((const char *,
00092 int));
00093 static struct file_hash_entry * file_hash_lookup PARAMS ((const char *));
00094 static struct demangled_hash_entry *
00095 demangled_hash_lookup PARAMS ((const char *, int));
00096 static void symbol_push PARAMS ((symbol *));
00097 static symbol * symbol_pop PARAMS ((void));
00098 static void file_push PARAMS ((file *));
00099 static file * file_pop PARAMS ((void));
00100 static void tlink_init PARAMS ((void));
00101 static int tlink_execute PARAMS ((const char *, char **, const char *));
00102 static char * frob_extension PARAMS ((const char *, const char *));
00103 static char * obstack_fgets PARAMS ((FILE *, struct obstack *));
00104 static char * tfgets PARAMS ((FILE *));
00105 static char * pfgets PARAMS ((FILE *));
00106 static void freadsym PARAMS ((FILE *, file *, int));
00107 static void read_repo_file PARAMS ((file *));
00108 static void maybe_tweak PARAMS ((char *, file *));
00109 static int recompile_files PARAMS ((void));
00110 static int read_repo_files PARAMS ((char **));
00111 static void demangle_new_symbols PARAMS ((void));
00112 static int scan_linker_output PARAMS ((const char *));
00113
00114
00115
00116 static struct symbol_hash_entry *
00117 symbol_hash_lookup (string, create)
00118 const char *string;
00119 int create;
00120 {
00121 PTR *e;
00122 e = htab_find_slot_with_hash (symbol_table, string,
00123 (*htab_hash_string) (string),
00124 create ? INSERT : NO_INSERT);
00125 if (e == NULL)
00126 return NULL;
00127 if (*e == NULL)
00128 {
00129 struct symbol_hash_entry *v;
00130 *e = v = xcalloc (1, sizeof (*v));
00131 v->key = xstrdup (string);
00132 }
00133 return *e;
00134 }
00135
00136 static htab_t file_table;
00137
00138
00139
00140 static struct file_hash_entry *
00141 file_hash_lookup (string)
00142 const char *string;
00143 {
00144 PTR *e;
00145 e = htab_find_slot_with_hash (file_table, string,
00146 (*htab_hash_string) (string),
00147 INSERT);
00148 if (*e == NULL)
00149 {
00150 struct file_hash_entry *v;
00151 *e = v = xcalloc (1, sizeof (*v));
00152 v->key = xstrdup (string);
00153 }
00154 return *e;
00155 }
00156
00157 static htab_t demangled_table;
00158
00159
00160
00161 static struct demangled_hash_entry *
00162 demangled_hash_lookup (string, create)
00163 const char *string;
00164 int create;
00165 {
00166 PTR *e;
00167 e = htab_find_slot_with_hash (demangled_table, string,
00168 (*htab_hash_string) (string),
00169 create ? INSERT : NO_INSERT);
00170 if (e == NULL)
00171 return NULL;
00172 if (*e == NULL)
00173 {
00174 struct demangled_hash_entry *v;
00175 *e = v = xcalloc (1, sizeof (*v));
00176 v->key = xstrdup (string);
00177 }
00178 return *e;
00179 }
00180
00181
00182
00183 struct symbol_stack_entry
00184 {
00185 symbol *value;
00186 struct symbol_stack_entry *next;
00187 };
00188 struct obstack symbol_stack_obstack;
00189 struct symbol_stack_entry *symbol_stack;
00190
00191 struct file_stack_entry
00192 {
00193 file *value;
00194 struct file_stack_entry *next;
00195 };
00196 struct obstack file_stack_obstack;
00197 struct file_stack_entry *file_stack;
00198
00199 static void
00200 symbol_push (p)
00201 symbol *p;
00202 {
00203 struct symbol_stack_entry *ep = (struct symbol_stack_entry *) obstack_alloc
00204 (&symbol_stack_obstack, sizeof (struct symbol_stack_entry));
00205 ep->value = p;
00206 ep->next = symbol_stack;
00207 symbol_stack = ep;
00208 }
00209
00210 static symbol *
00211 symbol_pop ()
00212 {
00213 struct symbol_stack_entry *ep = symbol_stack;
00214 symbol *p;
00215 if (ep == NULL)
00216 return NULL;
00217 p = ep->value;
00218 symbol_stack = ep->next;
00219 obstack_free (&symbol_stack_obstack, ep);
00220 return p;
00221 }
00222
00223 static void
00224 file_push (p)
00225 file *p;
00226 {
00227 struct file_stack_entry *ep;
00228
00229 if (p->tweaking)
00230 return;
00231
00232 ep = (struct file_stack_entry *) obstack_alloc
00233 (&file_stack_obstack, sizeof (struct file_stack_entry));
00234 ep->value = p;
00235 ep->next = file_stack;
00236 file_stack = ep;
00237 p->tweaking = 1;
00238 }
00239
00240 static file *
00241 file_pop ()
00242 {
00243 struct file_stack_entry *ep = file_stack;
00244 file *p;
00245 if (ep == NULL)
00246 return NULL;
00247 p = ep->value;
00248 file_stack = ep->next;
00249 obstack_free (&file_stack_obstack, ep);
00250 p->tweaking = 0;
00251 return p;
00252 }
00253
00254
00255
00256
00257
00258 static void
00259 tlink_init ()
00260 {
00261 const char *p;
00262
00263 symbol_table = htab_create (500, hash_string_hash, hash_string_eq,
00264 NULL);
00265 file_table = htab_create (500, hash_string_hash, hash_string_eq,
00266 NULL);
00267 demangled_table = htab_create (500, hash_string_hash, hash_string_eq,
00268 NULL);
00269
00270 obstack_begin (&symbol_stack_obstack, 0);
00271 obstack_begin (&file_stack_obstack, 0);
00272
00273 p = getenv ("TLINK_VERBOSE");
00274 if (p)
00275 tlink_verbose = atoi (p);
00276 else
00277 {
00278 tlink_verbose = 1;
00279 if (vflag)
00280 tlink_verbose = 2;
00281 if (debug)
00282 tlink_verbose = 3;
00283 }
00284 }
00285
00286 static int
00287 tlink_execute (prog, argv, redir)
00288 const char *prog;
00289 char **argv;
00290 const char *redir;
00291 {
00292 collect_execute (prog, argv, redir);
00293 return collect_wait (prog);
00294 }
00295
00296 static char *
00297 frob_extension (s, ext)
00298 const char *s;
00299 const char *ext;
00300 {
00301 const char *p = strrchr (s, '/');
00302 if (! p)
00303 p = s;
00304 p = strrchr (p, '.');
00305 if (! p)
00306 p = s + strlen (s);
00307
00308 obstack_grow (&temporary_obstack, s, p - s);
00309 return obstack_copy0 (&temporary_obstack, ext, strlen (ext));
00310 }
00311
00312 static char *
00313 obstack_fgets (stream, ob)
00314 FILE *stream;
00315 struct obstack *ob;
00316 {
00317 int c;
00318 while ((c = getc (stream)) != EOF && c != '\n')
00319 obstack_1grow (ob, c);
00320 if (obstack_object_size (ob) == 0)
00321 return NULL;
00322 obstack_1grow (ob, '\0');
00323 return obstack_finish (ob);
00324 }
00325
00326 static char *
00327 tfgets (stream)
00328 FILE *stream;
00329 {
00330 return obstack_fgets (stream, &temporary_obstack);
00331 }
00332
00333 static char *
00334 pfgets (stream)
00335 FILE *stream;
00336 {
00337 return xstrdup (tfgets (stream));
00338 }
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348 static void
00349 freadsym (stream, f, chosen)
00350 FILE *stream;
00351 file *f;
00352 int chosen;
00353 {
00354 symbol *sym;
00355
00356 {
00357 const char *name = tfgets (stream);
00358 sym = symbol_hash_lookup (name, true);
00359 }
00360
00361 if (sym->file == NULL)
00362 {
00363
00364
00365 symbol_push (sym);
00366 sym->file = f;
00367 sym->chosen = chosen;
00368 }
00369 else if (chosen)
00370 {
00371
00372
00373 if (sym->chosen && sym->file != f)
00374 {
00375 if (sym->chosen == 1)
00376 file_push (sym->file);
00377 else
00378 {
00379 file_push (f);
00380 f = sym->file;
00381 chosen = sym->chosen;
00382 }
00383 }
00384 sym->file = f;
00385 sym->chosen = chosen;
00386 }
00387 }
00388
00389
00390
00391 static void
00392 read_repo_file (f)
00393 file *f;
00394 {
00395 char c;
00396 FILE *stream = fopen (f->key, "r");
00397
00398 if (tlink_verbose >= 2)
00399 fprintf (stderr, _("collect: reading %s\n"), f->key);
00400
00401 while (fscanf (stream, "%c ", &c) == 1)
00402 {
00403 switch (c)
00404 {
00405 case 'A':
00406 f->args = pfgets (stream);
00407 break;
00408 case 'D':
00409 f->dir = pfgets (stream);
00410 break;
00411 case 'M':
00412 f->main = pfgets (stream);
00413 break;
00414 case 'P':
00415 freadsym (stream, f, 2);
00416 break;
00417 case 'C':
00418 freadsym (stream, f, 1);
00419 break;
00420 case 'O':
00421 freadsym (stream, f, 0);
00422 break;
00423 }
00424 obstack_free (&temporary_obstack, temporary_firstobj);
00425 }
00426 fclose (stream);
00427 if (f->args == NULL)
00428 f->args = getenv ("COLLECT_GCC_OPTIONS");
00429 if (f->dir == NULL)
00430 f->dir = ".";
00431 }
00432
00433
00434
00435
00436
00437
00438 static void
00439 maybe_tweak (line, f)
00440 char *line;
00441 file *f;
00442 {
00443 symbol *sym = symbol_hash_lookup (line + 2, false);
00444
00445 if ((sym->file == f && sym->tweaking)
00446 || (sym->file != f && line[0] == 'C'))
00447 {
00448 sym->tweaking = 0;
00449 sym->tweaked = 1;
00450
00451 if (line[0] == 'O')
00452 line[0] = 'C';
00453 else
00454 line[0] = 'O';
00455 }
00456 }
00457
00458
00459
00460
00461
00462
00463 static int
00464 recompile_files ()
00465 {
00466 file *f;
00467
00468 putenv (xstrdup ("COMPILER_PATH="));
00469 putenv (xstrdup ("LIBRARY_PATH="));
00470
00471 while ((f = file_pop ()) != NULL)
00472 {
00473 char *line, *command;
00474 FILE *stream = fopen (f->key, "r");
00475 const char *const outname = frob_extension (f->key, ".rnw");
00476 FILE *output = fopen (outname, "w");
00477
00478 while ((line = tfgets (stream)) != NULL)
00479 {
00480 switch (line[0])
00481 {
00482 case 'C':
00483 case 'O':
00484 maybe_tweak (line, f);
00485 }
00486 fprintf (output, "%s\n", line);
00487 }
00488 fclose (stream);
00489 fclose (output);
00490 rename (outname, f->key);
00491
00492 obstack_grow (&temporary_obstack, "cd ", 3);
00493 obstack_grow (&temporary_obstack, f->dir, strlen (f->dir));
00494 obstack_grow (&temporary_obstack, "; ", 2);
00495 obstack_grow (&temporary_obstack, c_file_name, strlen (c_file_name));
00496 obstack_1grow (&temporary_obstack, ' ');
00497 obstack_grow (&temporary_obstack, f->args, strlen (f->args));
00498 obstack_1grow (&temporary_obstack, ' ');
00499 command = obstack_copy0 (&temporary_obstack, f->main, strlen (f->main));
00500
00501 if (tlink_verbose)
00502 fprintf (stderr, _("collect: recompiling %s\n"), f->main);
00503 if (tlink_verbose >= 3)
00504 fprintf (stderr, "%s\n", command);
00505
00506 if (system (command) != 0)
00507 return 0;
00508
00509 read_repo_file (f);
00510
00511 obstack_free (&temporary_obstack, temporary_firstobj);
00512 }
00513 return 1;
00514 }
00515
00516
00517
00518
00519 static int
00520 read_repo_files (object_lst)
00521 char **object_lst;
00522 {
00523 char **object = object_lst;
00524
00525 for (; *object; object++)
00526 {
00527 const char *p;
00528 file *f;
00529
00530
00531 if (*object[0] == '-')
00532 continue;
00533
00534 p = frob_extension (*object, ".rpo");
00535
00536 if (! file_exists (p))
00537 continue;
00538
00539 f = file_hash_lookup (p);
00540
00541 read_repo_file (f);
00542 }
00543
00544 if (file_stack != NULL && ! recompile_files ())
00545 return 0;
00546
00547 return (symbol_stack != NULL);
00548 }
00549
00550
00551
00552 static void
00553 demangle_new_symbols ()
00554 {
00555 symbol *sym;
00556
00557 while ((sym = symbol_pop ()) != NULL)
00558 {
00559 demangled *dem;
00560 const char *p = cplus_demangle (sym->key, DMGL_PARAMS | DMGL_ANSI);
00561
00562 if (! p)
00563 continue;
00564
00565 dem = demangled_hash_lookup (p, true);
00566 dem->mangled = sym->key;
00567 }
00568 }
00569
00570
00571
00572
00573 static int
00574 scan_linker_output (fname)
00575 const char *fname;
00576 {
00577 FILE *stream = fopen (fname, "r");
00578 char *line;
00579
00580 while ((line = tfgets (stream)) != NULL)
00581 {
00582 char *p = line, *q;
00583 symbol *sym;
00584 int end;
00585
00586 while (*p && ISSPACE ((unsigned char) *p))
00587 ++p;
00588
00589 if (! *p)
00590 continue;
00591
00592 for (q = p; *q && ! ISSPACE ((unsigned char) *q); ++q)
00593 ;
00594
00595
00596 if (*p == '.')
00597 ++p;
00598 if (!strncmp (p, USER_LABEL_PREFIX, strlen (USER_LABEL_PREFIX)))
00599 p += strlen (USER_LABEL_PREFIX);
00600
00601 end = ! *q;
00602 *q = 0;
00603 sym = symbol_hash_lookup (p, false);
00604
00605
00606
00607
00608 if (! sym && ! end && strstr (q + 1, "Undefined symbol: "))
00609 {
00610 char *p = strrchr (q + 1, ' ');
00611 p++;
00612 if (*p == '.')
00613 p++;
00614 if (!strncmp (p, USER_LABEL_PREFIX, strlen (USER_LABEL_PREFIX)))
00615 p += strlen (USER_LABEL_PREFIX);
00616 sym = symbol_hash_lookup (p, false);
00617 }
00618
00619 if (! sym && ! end)
00620
00621 {
00622 const char *oldq = q + 1;
00623 demangled *dem = 0;
00624 q = 0;
00625
00626
00627 p = strchr (oldq, '`');
00628 if (p)
00629 p++, q = strchr (p, '\'');
00630
00631 else if (p = strchr (oldq, '"'), p)
00632 p++, q = strchr (p, '"');
00633
00634 if (p)
00635 {
00636
00637
00638 p[-1] = '\0';
00639
00640
00641 if (*p == '.')
00642 p++;
00643 }
00644
00645
00646
00647 if (q && (strstr (oldq, "ndefined")
00648 || strstr (oldq, "nresolved")
00649 || strstr (oldq, "nsatisfied")
00650 || strstr (oldq, "ultiple")))
00651 {
00652 *q = 0;
00653 dem = demangled_hash_lookup (p, false);
00654 if (dem)
00655 sym = symbol_hash_lookup (dem->mangled, false);
00656 else
00657 {
00658 if (!strncmp (p, USER_LABEL_PREFIX,
00659 strlen (USER_LABEL_PREFIX)))
00660 p += strlen (USER_LABEL_PREFIX);
00661 sym = symbol_hash_lookup (p, false);
00662 }
00663 }
00664 }
00665
00666 if (sym && sym->tweaked)
00667 {
00668 fclose (stream);
00669 return 0;
00670 }
00671 if (sym && !sym->tweaking)
00672 {
00673 if (tlink_verbose >= 2)
00674 fprintf (stderr, _("collect: tweaking %s in %s\n"),
00675 sym->key, sym->file->key);
00676 sym->tweaking = 1;
00677 file_push (sym->file);
00678 }
00679
00680 obstack_free (&temporary_obstack, temporary_firstobj);
00681 }
00682
00683 fclose (stream);
00684 return (file_stack != NULL);
00685 }
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696 void
00697 do_tlink (ld_argv, object_lst)
00698 char **ld_argv, **object_lst ATTRIBUTE_UNUSED;
00699 {
00700 int exit = tlink_execute ("ld", ld_argv, ldout);
00701
00702 tlink_init ();
00703
00704 if (exit)
00705 {
00706 int i = 0;
00707
00708
00709
00710 if (read_repo_files (ld_argv))
00711 while (exit && i++ < MAX_ITERATIONS)
00712 {
00713 if (tlink_verbose >= 3)
00714 dump_file (ldout);
00715 demangle_new_symbols ();
00716 if (! scan_linker_output (ldout))
00717 break;
00718 if (! recompile_files ())
00719 break;
00720 if (tlink_verbose)
00721 fprintf (stderr, _("collect: relinking\n"));
00722 exit = tlink_execute ("ld", ld_argv, ldout);
00723 }
00724 }
00725
00726 dump_file (ldout);
00727 unlink (ldout);
00728 if (exit)
00729 {
00730 error ("ld returned %d exit status", exit);
00731 collect_exit (exit);
00732 }
00733 }