tlink.c 16.4 KB
Newer Older
1 2 3
/* Scan linker error messages for missing template instantiations and provide
   them.

4
   Copyright (C) 1995, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
5 6
   Contributed by Jason Merrill (jason@cygnus.com).

7
This file is part of GCC.
8

9 10 11 12
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
13

14 15 16 17
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.
18 19

You should have received a copy of the GNU General Public License
20 21 22
along with GCC; see the file COPYING.  If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.  */
23 24

#include "config.h"
25
#include "system.h"
26 27
#include "coretypes.h"
#include "tm.h"
28
#include "intl.h"
29 30
#include "obstack.h"
#include "hashtab.h"
31
#include "demangle.h"
32
#include "collect2.h"
33 34 35 36 37 38 39 40

#define MAX_ITERATIONS 17

/* Defined in the automatically-generated underscore.c.  */
extern int prepends_underscore;

static int tlink_verbose;

41
/* Hash table boilerplate for working with htab_t.  We have hash tables
Jason Merrill committed
42
   for symbol names, file names, and demangled symbols.  */
43 44 45

typedef struct symbol_hash_entry
{
46
  const char *key;
47 48 49 50 51 52 53 54
  struct file_hash_entry *file;
  int chosen;
  int tweaking;
  int tweaked;
} symbol;

typedef struct file_hash_entry
{
55
  const char *key;
56 57 58 59 60 61 62 63
  const char *args;
  const char *dir;
  const char *main;
  int tweaking;
} file;

typedef struct demangled_hash_entry
{
64
  const char *key;
65 66 67
  const char *mangled;
} demangled;

68 69 70 71 72 73 74 75 76 77
/* Hash and comparison functions for these hash tables.  */

static int hash_string_eq PARAMS ((const void *, const void *));
static hashval_t hash_string_hash PARAMS ((const void *));

static int
hash_string_eq (s1_p, s2_p)
     const void *s1_p;
     const void *s2_p;
{
Kazu Hirata committed
78 79
  const char *const *s1 = (const char *const *) s1_p;
  const char *s2 = (const char *) s2_p;
80 81 82 83 84 85 86
  return strcmp (*s1, s2) == 0;
}

static hashval_t
hash_string_hash (s_p)
     const void *s_p;
{
Kazu Hirata committed
87
  const char *const *s = (const char *const *) s_p;
88 89 90 91
  return (*htab_hash_string) (*s);
}

static htab_t symbol_table;
92

Kaveh R. Ghazi committed
93
static struct symbol_hash_entry * symbol_hash_lookup PARAMS ((const char *,
94
							      int));
Kaveh R. Ghazi committed
95 96
static struct file_hash_entry * file_hash_lookup PARAMS ((const char *));
static struct demangled_hash_entry *
97
  demangled_hash_lookup PARAMS ((const char *, int));
Kaveh R. Ghazi committed
98 99 100 101 102
static void symbol_push PARAMS ((symbol *));
static symbol * symbol_pop PARAMS ((void));
static void file_push PARAMS ((file *));
static file * file_pop PARAMS ((void));
static void tlink_init PARAMS ((void));
103 104
static int tlink_execute PARAMS ((const char *, char **, const char *));
static char * frob_extension PARAMS ((const char *, const char *));
Kaveh R. Ghazi committed
105 106 107 108 109 110 111 112 113 114 115
static char * obstack_fgets PARAMS ((FILE *, struct obstack *));
static char * tfgets PARAMS ((FILE *));
static char * pfgets PARAMS ((FILE *));
static void freadsym PARAMS ((FILE *, file *, int));
static void read_repo_file PARAMS ((file *));
static void maybe_tweak PARAMS ((char *, file *));
static int recompile_files PARAMS ((void));
static int read_repo_files PARAMS ((char **));
static void demangle_new_symbols PARAMS ((void));
static int scan_linker_output PARAMS ((const char *));

Jason Merrill committed
116 117
/* Look up an entry in the symbol hash table.  */

118 119 120
static struct symbol_hash_entry *
symbol_hash_lookup (string, create)
     const char *string;
121
     int create;
122
{
123 124
  PTR *e;
  e = htab_find_slot_with_hash (symbol_table, string,
Kazu Hirata committed
125
				(*htab_hash_string) (string),
126 127 128 129
				create ? INSERT : NO_INSERT);
  if (e == NULL)
    return NULL;
  if (*e == NULL)
130
    {
131 132 133
      struct symbol_hash_entry *v;
      *e = v = xcalloc (1, sizeof (*v));
      v->key = xstrdup (string);
134
    }
135
  return *e;
136 137
}

138 139
static htab_t file_table;

Jason Merrill committed
140 141
/* Look up an entry in the file hash table.  */

142 143 144 145
static struct file_hash_entry *
file_hash_lookup (string)
     const char *string;
{
146 147
  PTR *e;
  e = htab_find_slot_with_hash (file_table, string,
Kazu Hirata committed
148
				(*htab_hash_string) (string),
149 150
				INSERT);
  if (*e == NULL)
151
    {
152 153 154
      struct file_hash_entry *v;
      *e = v = xcalloc (1, sizeof (*v));
      v->key = xstrdup (string);
155
    }
156
  return *e;
157 158
}

159 160
static htab_t demangled_table;

Jason Merrill committed
161 162
/* Look up an entry in the demangled name hash table.  */

163 164 165
static struct demangled_hash_entry *
demangled_hash_lookup (string, create)
     const char *string;
166
     int create;
167
{
168 169
  PTR *e;
  e = htab_find_slot_with_hash (demangled_table, string,
Kazu Hirata committed
170
				(*htab_hash_string) (string),
171 172 173 174 175 176 177 178 179 180
				create ? INSERT : NO_INSERT);
  if (e == NULL)
    return NULL;
  if (*e == NULL)
    {
      struct demangled_hash_entry *v;
      *e = v = xcalloc (1, sizeof (*v));
      v->key = xstrdup (string);
    }
  return *e;
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
}

/* Stack code.  */

struct symbol_stack_entry
{
  symbol *value;
  struct symbol_stack_entry *next;
};
struct obstack symbol_stack_obstack;
struct symbol_stack_entry *symbol_stack;

struct file_stack_entry
{
  file *value;
  struct file_stack_entry *next;
};
struct obstack file_stack_obstack;
struct file_stack_entry *file_stack;

static void
symbol_push (p)
     symbol *p;
{
  struct symbol_stack_entry *ep = (struct symbol_stack_entry *) obstack_alloc
    (&symbol_stack_obstack, sizeof (struct symbol_stack_entry));
  ep->value = p;
  ep->next = symbol_stack;
  symbol_stack = ep;
}

static symbol *
symbol_pop ()
{
  struct symbol_stack_entry *ep = symbol_stack;
  symbol *p;
  if (ep == NULL)
    return NULL;
  p = ep->value;
  symbol_stack = ep->next;
  obstack_free (&symbol_stack_obstack, ep);
  return p;
}

static void
file_push (p)
     file *p;
{
  struct file_stack_entry *ep;

  if (p->tweaking)
    return;

  ep = (struct file_stack_entry *) obstack_alloc
    (&file_stack_obstack, sizeof (struct file_stack_entry));
  ep->value = p;
  ep->next = file_stack;
  file_stack = ep;
  p->tweaking = 1;
}

static file *
file_pop ()
{
  struct file_stack_entry *ep = file_stack;
  file *p;
  if (ep == NULL)
    return NULL;
  p = ep->value;
  file_stack = ep->next;
  obstack_free (&file_stack_obstack, ep);
  p->tweaking = 0;
  return p;
}

/* Other machinery.  */

Jason Merrill committed
258 259
/* Initialize the tlink machinery.  Called from do_tlink.  */

260 261 262
static void
tlink_init ()
{
263
  const char *p;
264

265 266 267 268 269 270 271
  symbol_table = htab_create (500, hash_string_hash, hash_string_eq,
			      NULL);
  file_table = htab_create (500, hash_string_hash, hash_string_eq,
			    NULL);
  demangled_table = htab_create (500, hash_string_hash, hash_string_eq,
				 NULL);
  
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
  obstack_begin (&symbol_stack_obstack, 0);
  obstack_begin (&file_stack_obstack, 0);

  p = getenv ("TLINK_VERBOSE");
  if (p)
    tlink_verbose = atoi (p);
  else
    {
      tlink_verbose = 1;
      if (vflag)
	tlink_verbose = 2;
      if (debug)
	tlink_verbose = 3;
    }
}

static int
tlink_execute (prog, argv, redir)
290
     const char *prog;
291
     char **argv;
292
     const char *redir;
293 294 295
{
  collect_execute (prog, argv, redir);
  return collect_wait (prog);
Kazu Hirata committed
296
}
297 298 299

static char *
frob_extension (s, ext)
300
     const char *s;
Kaveh R. Ghazi committed
301
     const char *ext;
302
{
303
  const char *p = strrchr (s, '/');
304 305
  if (! p)
    p = s;
306
  p = strrchr (p, '.');
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
  if (! p)
    p = s + strlen (s);

  obstack_grow (&temporary_obstack, s, p - s);
  return obstack_copy0 (&temporary_obstack, ext, strlen (ext));
}

static char *
obstack_fgets (stream, ob)
     FILE *stream;
     struct obstack *ob;
{
  int c;
  while ((c = getc (stream)) != EOF && c != '\n')
    obstack_1grow (ob, c);
  if (obstack_object_size (ob) == 0)
    return NULL;
  obstack_1grow (ob, '\0');
  return obstack_finish (ob);
}

static char *
tfgets (stream)
     FILE *stream;
{
  return obstack_fgets (stream, &temporary_obstack);
}

static char *
pfgets (stream)
     FILE *stream;
{
Geoffrey Keating committed
339
  return xstrdup (tfgets (stream));
340 341 342 343
}

/* Real tlink code.  */

Jason Merrill committed
344 345 346 347 348 349
/* Subroutine of read_repo_file.  We are reading the repo file for file F,
   which is coming in on STREAM, and the symbol that comes next in STREAM
   is offerred, chosen or provided if CHOSEN is 0, 1 or 2, respectively.

   XXX "provided" is unimplemented, both here and in the compiler.  */

350 351 352 353 354 355 356 357 358
static void
freadsym (stream, f, chosen)
     FILE *stream;
     file *f;
     int chosen;
{
  symbol *sym;

  {
359
    const char *name = tfgets (stream);
360 361 362 363 364
    sym = symbol_hash_lookup (name, true);
  }

  if (sym->file == NULL)
    {
Jason Merrill committed
365 366
      /* We didn't have this symbol already, so we choose this file.  */

367 368 369 370 371 372
      symbol_push (sym);
      sym->file = f;
      sym->chosen = chosen;
    }
  else if (chosen)
    {
Jason Merrill committed
373 374
      /* We want this file; cast aside any pretender.  */

375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
      if (sym->chosen && sym->file != f)
	{
	  if (sym->chosen == 1)
	    file_push (sym->file);
	  else
	    {
	      file_push (f);
	      f = sym->file;
	      chosen = sym->chosen;
	    }
	}
      sym->file = f;
      sym->chosen = chosen;
    }
}

Jason Merrill committed
391 392
/* Read in the repo file denoted by F, and record all its information.  */

393 394 395 396 397
static void
read_repo_file (f)
     file *f;
{
  char c;
398
  FILE *stream = fopen (f->key, "r");
399 400

  if (tlink_verbose >= 2)
401
    fprintf (stderr, _("collect: reading %s\n"), f->key);
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434

  while (fscanf (stream, "%c ", &c) == 1)
    {
      switch (c)
	{
	case 'A':
	  f->args = pfgets (stream);
	  break;
	case 'D':
	  f->dir = pfgets (stream);
	  break;
	case 'M':
	  f->main = pfgets (stream);
	  break;
	case 'P':
	  freadsym (stream, f, 2);
	  break;
	case 'C':
	  freadsym (stream, f, 1);
	  break;
	case 'O':
	  freadsym (stream, f, 0);
	  break;
	}
      obstack_free (&temporary_obstack, temporary_firstobj);
    }
  fclose (stream);
  if (f->args == NULL)
    f->args = getenv ("COLLECT_GCC_OPTIONS");
  if (f->dir == NULL)
    f->dir = ".";
}

Jason Merrill committed
435 436 437 438 439
/* We might want to modify LINE, which is a symbol line from file F.  We do
   this if either we saw an error message referring to the symbol in
   question, or we have already allocated the symbol to another file and
   this one wants to emit it as well.  */

440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459
static void
maybe_tweak (line, f)
     char *line;
     file *f;
{
  symbol *sym = symbol_hash_lookup (line + 2, false);

  if ((sym->file == f && sym->tweaking)
      || (sym->file != f && line[0] == 'C'))
    {
      sym->tweaking = 0;
      sym->tweaked = 1;

      if (line[0] == 'O')
	line[0] = 'C';
      else
	line[0] = 'O';
    }
}

Jason Merrill committed
460 461 462 463 464
/* Update the repo files for each of the object files we have adjusted and
   recompile.

   XXX Should this use collect_execute instead of system?  */

465 466 467 468 469
static int
recompile_files ()
{
  file *f;

470 471
  putenv (xstrdup ("COMPILER_PATH"));
  putenv (xstrdup ("LIBRARY_PATH"));
Kazu Hirata committed
472

473 474 475
  while ((f = file_pop ()) != NULL)
    {
      char *line, *command;
476 477
      FILE *stream = fopen (f->key, "r");
      const char *const outname = frob_extension (f->key, ".rnw");
478 479 480 481 482 483 484 485 486 487 488 489 490 491
      FILE *output = fopen (outname, "w");

      while ((line = tfgets (stream)) != NULL)
	{
	  switch (line[0])
	    {
	    case 'C':
	    case 'O':
	      maybe_tweak (line, f);
	    }
	  fprintf (output, "%s\n", line);
	}
      fclose (stream);
      fclose (output);
492
      rename (outname, f->key);
493 494 495 496 497 498 499 500 501 502 503

      obstack_grow (&temporary_obstack, "cd ", 3);
      obstack_grow (&temporary_obstack, f->dir, strlen (f->dir));
      obstack_grow (&temporary_obstack, "; ", 2);
      obstack_grow (&temporary_obstack, c_file_name, strlen (c_file_name));
      obstack_1grow (&temporary_obstack, ' ');
      obstack_grow (&temporary_obstack, f->args, strlen (f->args));
      obstack_1grow (&temporary_obstack, ' ');
      command = obstack_copy0 (&temporary_obstack, f->main, strlen (f->main));

      if (tlink_verbose)
504
	fprintf (stderr, _("collect: recompiling %s\n"), f->main);
505 506 507 508 509 510 511 512 513 514 515 516 517
      if (tlink_verbose >= 3)
	fprintf (stderr, "%s\n", command);

      if (system (command) != 0)
	return 0;

      read_repo_file (f);

      obstack_free (&temporary_obstack, temporary_firstobj);
    }
  return 1;
}

Jason Merrill committed
518 519 520
/* The first phase of processing: determine which object files have
   .rpo files associated with them, and read in the information.  */

521 522 523 524 525 526 527 528
static int
read_repo_files (object_lst)
     char **object_lst;
{
  char **object = object_lst;

  for (; *object; object++)
    {
529
      const char *p;
530 531
      file *f;

532 533 534 535 536 537
      /* Don't bother trying for ld flags.  */
      if (*object[0] == '-')
	continue;

      p = frob_extension (*object, ".rpo");

538 539 540 541 542 543 544 545 546 547 548 549 550 551
      if (! file_exists (p))
	continue;

      f = file_hash_lookup (p);

      read_repo_file (f);
    }

  if (file_stack != NULL && ! recompile_files ())
    return 0;

  return (symbol_stack != NULL);
}

Jason Merrill committed
552 553
/* Add the demangled forms of any new symbols to the hash table.  */

554 555 556 557 558 559 560 561
static void
demangle_new_symbols ()
{
  symbol *sym;

  while ((sym = symbol_pop ()) != NULL)
    {
      demangled *dem;
562
      const char *p = cplus_demangle (sym->key, DMGL_PARAMS | DMGL_ANSI);
563 564 565 566 567

      if (! p)
	continue;

      dem = demangled_hash_lookup (p, true);
568
      dem->mangled = sym->key;
569 570 571
    }
}

Jason Merrill committed
572 573 574
/* Step through the output of the linker, in the file named FNAME, and
   adjust the settings for each symbol encountered.  */

575 576
static int
scan_linker_output (fname)
Kaveh R. Ghazi committed
577
     const char *fname;
578 579 580 581 582 583 584 585 586
{
  FILE *stream = fopen (fname, "r");
  char *line;

  while ((line = tfgets (stream)) != NULL)
    {
      char *p = line, *q;
      symbol *sym;
      int end;
Kazu Hirata committed
587

Kazu Hirata committed
588
      while (*p && ISSPACE ((unsigned char) *p))
589 590 591 592 593
	++p;

      if (! *p)
	continue;

Kazu Hirata committed
594
      for (q = p; *q && ! ISSPACE ((unsigned char) *q); ++q)
595 596 597 598 599
	;

      /* Try the first word on the line.  */
      if (*p == '.')
	++p;
600 601
      if (!strncmp (p, USER_LABEL_PREFIX, strlen (USER_LABEL_PREFIX)))
	p += strlen (USER_LABEL_PREFIX);
602 603 604 605 606

      end = ! *q;
      *q = 0;
      sym = symbol_hash_lookup (p, false);

607 608 609
      /* Some SVR4 linkers produce messages like
	 ld: 0711-317 ERROR: Undefined symbol: .g__t3foo1Zi
	 */
Kazu Hirata committed
610
      if (! sym && ! end && strstr (q + 1, "Undefined symbol: "))
611
	{
Kazu Hirata committed
612
	  char *p = strrchr (q + 1, ' ');
613 614 615
	  p++;
	  if (*p == '.')
	    p++;
616 617
	  if (!strncmp (p, USER_LABEL_PREFIX, strlen (USER_LABEL_PREFIX)))
	    p += strlen (USER_LABEL_PREFIX);
618 619 620
	  sym = symbol_hash_lookup (p, false);
	}

621
      if (! sym && ! end)
622
	/* Try a mangled name in quotes.  */
623
	{
Kazu Hirata committed
624
	  const char *oldq = q + 1;
625 626 627
	  demangled *dem = 0;
	  q = 0;

628
	  /* First try `GNU style'.  */
629
	  p = strchr (oldq, '`');
630
	  if (p)
631
	    p++, q = strchr (p, '\'');
632
	  /* Then try "double quotes".  */
633 634
	  else if (p = strchr (oldq, '"'), p)
	    p++, q = strchr (p, '"');
635

636 637 638 639 640
	  /* Don't let the strstr's below see the demangled name; we
	     might get spurious matches.  */
	  if (p)
	    p[-1] = '\0';

641 642 643
	  /* We need to check for certain error keywords here, or we would
	     mistakenly use GNU ld's "In function `foo':" message.  */
	  if (q && (strstr (oldq, "ndefined")
Jason Merrill committed
644
		    || strstr (oldq, "nresolved")
645
		    || strstr (oldq, "nsatisfied")
646
		    || strstr (oldq, "ultiple")))
647
	    {
648 649 650 651 652
	      *q = 0;
	      dem = demangled_hash_lookup (p, false);
	      if (dem)
		sym = symbol_hash_lookup (dem->mangled, false);
	      else
Kazu Hirata committed
653
		{
654 655 656
		  if (!strncmp (p, USER_LABEL_PREFIX,
				strlen (USER_LABEL_PREFIX)))
		    p += strlen (USER_LABEL_PREFIX);
657 658
		  sym = symbol_hash_lookup (p, false);
		}
659 660 661 662
	    }
	}

      if (sym && sym->tweaked)
663 664 665 666
	{
	  fclose (stream);
	  return 0;
	}
667 668 669
      if (sym && !sym->tweaking)
	{
	  if (tlink_verbose >= 2)
670
	    fprintf (stderr, _("collect: tweaking %s in %s\n"),
671
		     sym->key, sym->file->key);
672 673 674
	  sym->tweaking = 1;
	  file_push (sym->file);
	}
Kazu Hirata committed
675

676 677 678
      obstack_free (&temporary_obstack, temporary_firstobj);
    }

679
  fclose (stream);
680 681 682
  return (file_stack != NULL);
}

Jason Merrill committed
683 684 685 686 687 688 689 690 691
/* Entry point for tlink.  Called from main in collect2.c.

   Iteratively try to provide definitions for all the unresolved symbols
   mentioned in the linker error messages.

   LD_ARGV is an array of arguments for the linker.
   OBJECT_LST is an array of object files that we may be able to recompile
     to provide missing definitions.  Currently ignored.  */

692 693
void
do_tlink (ld_argv, object_lst)
694
     char **ld_argv, **object_lst ATTRIBUTE_UNUSED;
695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716
{
  int exit = tlink_execute ("ld", ld_argv, ldout);

  tlink_init ();

  if (exit)
    {
      int i = 0;

      /* Until collect does a better job of figuring out which are object
	 files, assume that everything on the command line could be.  */
      if (read_repo_files (ld_argv))
	while (exit && i++ < MAX_ITERATIONS)
	  {
	    if (tlink_verbose >= 3)
	      dump_file (ldout);
	    demangle_new_symbols ();
	    if (! scan_linker_output (ldout))
	      break;
	    if (! recompile_files ())
	      break;
	    if (tlink_verbose)
717
	      fprintf (stderr, _("collect: relinking\n"));
718 719 720 721 722 723 724 725 726 727 728 729
	    exit = tlink_execute ("ld", ld_argv, ldout);
	  }
    }

  dump_file (ldout);
  unlink (ldout);
  if (exit)
    {
      error ("ld returned %d exit status", exit);
      collect_exit (exit);
    }
}