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