]>
Commit | Line | Data |
---|---|---|
94ca3aab | 1 | /* Scan linker error messages for missing template instantiations and provide |
2 | them. | |
3 | ||
9c811526 | 4 | Copyright (C) 1995, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. |
94ca3aab | 5 | Contributed by Jason Merrill (jason@cygnus.com). |
6 | ||
f12b58b3 | 7 | This file is part of GCC. |
94ca3aab | 8 | |
f12b58b3 | 9 | GCC is free software; you can redistribute it and/or modify it under |
10 | the terms of the GNU General Public License as published by the Free | |
11 | Software Foundation; either version 2, or (at your option) any later | |
12 | version. | |
94ca3aab | 13 | |
f12b58b3 | 14 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
15 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
16 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
17 | for more details. | |
94ca3aab | 18 | |
19 | You should have received a copy of the GNU General Public License | |
f12b58b3 | 20 | along with GCC; see the file COPYING. If not, write to the Free |
21 | Software Foundation, 59 Temple Place - Suite 330, Boston, MA | |
22 | 02111-1307, USA. */ | |
94ca3aab | 23 | |
94ca3aab | 24 | #include "config.h" |
405711de | 25 | #include "system.h" |
6e6e5faa | 26 | #include "intl.h" |
1f3233d1 | 27 | #include "obstack.h" |
28 | #include "hashtab.h" | |
94ca3aab | 29 | #include "demangle.h" |
1ae13971 | 30 | #include "collect2.h" |
94ca3aab | 31 | |
32 | #define MAX_ITERATIONS 17 | |
33 | ||
34 | /* Obstack allocation and deallocation routines. */ | |
35 | #define obstack_chunk_alloc xmalloc | |
36 | #define obstack_chunk_free free | |
37 | ||
94ca3aab | 38 | /* Defined in the automatically-generated underscore.c. */ |
39 | extern int prepends_underscore; | |
40 | ||
41 | static int tlink_verbose; | |
42 | \f | |
1f3233d1 | 43 | /* Hash table boilerplate for working with htab_t. We have hash tables |
56e06438 | 44 | for symbol names, file names, and demangled symbols. */ |
94ca3aab | 45 | |
46 | typedef struct symbol_hash_entry | |
47 | { | |
1f3233d1 | 48 | const char *key; |
94ca3aab | 49 | struct file_hash_entry *file; |
50 | int chosen; | |
51 | int tweaking; | |
52 | int tweaked; | |
53 | } symbol; | |
54 | ||
55 | typedef struct file_hash_entry | |
56 | { | |
1f3233d1 | 57 | const char *key; |
94ca3aab | 58 | const char *args; |
59 | const char *dir; | |
60 | const char *main; | |
61 | int tweaking; | |
62 | } file; | |
63 | ||
64 | typedef struct demangled_hash_entry | |
65 | { | |
1f3233d1 | 66 | const char *key; |
94ca3aab | 67 | const char *mangled; |
68 | } demangled; | |
69 | ||
1f3233d1 | 70 | /* Hash and comparison functions for these hash tables. */ |
71 | ||
72 | static int hash_string_eq PARAMS ((const void *, const void *)); | |
73 | static hashval_t hash_string_hash PARAMS ((const void *)); | |
74 | ||
75 | static int | |
76 | hash_string_eq (s1_p, s2_p) | |
77 | const void *s1_p; | |
78 | const void *s2_p; | |
79 | { | |
80 | const char *const *s1 = (const char *const *)s1_p; | |
81 | const char *s2 = (const char *)s2_p; | |
82 | return strcmp (*s1, s2) == 0; | |
83 | } | |
84 | ||
85 | static hashval_t | |
86 | hash_string_hash (s_p) | |
87 | const void *s_p; | |
88 | { | |
89 | const char *const *s = (const char *const *)s_p; | |
90 | return (*htab_hash_string) (*s); | |
91 | } | |
92 | ||
93 | static htab_t symbol_table; | |
94ca3aab | 94 | |
0809af09 | 95 | static struct symbol_hash_entry * symbol_hash_lookup PARAMS ((const char *, |
229e4325 | 96 | int)); |
0809af09 | 97 | static struct file_hash_entry * file_hash_lookup PARAMS ((const char *)); |
0809af09 | 98 | static struct demangled_hash_entry * |
229e4325 | 99 | demangled_hash_lookup PARAMS ((const char *, int)); |
0809af09 | 100 | static void symbol_push PARAMS ((symbol *)); |
101 | static symbol * symbol_pop PARAMS ((void)); | |
102 | static void file_push PARAMS ((file *)); | |
103 | static file * file_pop PARAMS ((void)); | |
104 | static void tlink_init PARAMS ((void)); | |
e504db4a | 105 | static int tlink_execute PARAMS ((const char *, char **, const char *)); |
106 | static char * frob_extension PARAMS ((const char *, const char *)); | |
0809af09 | 107 | static char * obstack_fgets PARAMS ((FILE *, struct obstack *)); |
108 | static char * tfgets PARAMS ((FILE *)); | |
109 | static char * pfgets PARAMS ((FILE *)); | |
110 | static void freadsym PARAMS ((FILE *, file *, int)); | |
111 | static void read_repo_file PARAMS ((file *)); | |
112 | static void maybe_tweak PARAMS ((char *, file *)); | |
113 | static int recompile_files PARAMS ((void)); | |
114 | static int read_repo_files PARAMS ((char **)); | |
115 | static void demangle_new_symbols PARAMS ((void)); | |
116 | static int scan_linker_output PARAMS ((const char *)); | |
117 | ||
56e06438 | 118 | /* Look up an entry in the symbol hash table. */ |
119 | ||
94ca3aab | 120 | static struct symbol_hash_entry * |
121 | symbol_hash_lookup (string, create) | |
122 | const char *string; | |
229e4325 | 123 | int create; |
94ca3aab | 124 | { |
1f3233d1 | 125 | PTR *e; |
126 | e = htab_find_slot_with_hash (symbol_table, string, | |
127 | (*htab_hash_string)(string), | |
128 | create ? INSERT : NO_INSERT); | |
129 | if (e == NULL) | |
130 | return NULL; | |
131 | if (*e == NULL) | |
94ca3aab | 132 | { |
1f3233d1 | 133 | struct symbol_hash_entry *v; |
134 | *e = v = xcalloc (1, sizeof (*v)); | |
135 | v->key = xstrdup (string); | |
94ca3aab | 136 | } |
1f3233d1 | 137 | return *e; |
94ca3aab | 138 | } |
139 | ||
1f3233d1 | 140 | static htab_t file_table; |
141 | ||
56e06438 | 142 | /* Look up an entry in the file hash table. */ |
143 | ||
94ca3aab | 144 | static struct file_hash_entry * |
145 | file_hash_lookup (string) | |
146 | const char *string; | |
147 | { | |
1f3233d1 | 148 | PTR *e; |
149 | e = htab_find_slot_with_hash (file_table, string, | |
150 | (*htab_hash_string)(string), | |
151 | INSERT); | |
152 | if (*e == NULL) | |
94ca3aab | 153 | { |
1f3233d1 | 154 | struct file_hash_entry *v; |
155 | *e = v = xcalloc (1, sizeof (*v)); | |
156 | v->key = xstrdup (string); | |
94ca3aab | 157 | } |
1f3233d1 | 158 | return *e; |
94ca3aab | 159 | } |
160 | ||
1f3233d1 | 161 | static htab_t demangled_table; |
162 | ||
56e06438 | 163 | /* Look up an entry in the demangled name hash table. */ |
164 | ||
94ca3aab | 165 | static struct demangled_hash_entry * |
166 | demangled_hash_lookup (string, create) | |
167 | const char *string; | |
229e4325 | 168 | int create; |
94ca3aab | 169 | { |
1f3233d1 | 170 | PTR *e; |
171 | e = htab_find_slot_with_hash (demangled_table, string, | |
172 | (*htab_hash_string)(string), | |
173 | create ? INSERT : NO_INSERT); | |
174 | if (e == NULL) | |
175 | return NULL; | |
176 | if (*e == NULL) | |
177 | { | |
178 | struct demangled_hash_entry *v; | |
179 | *e = v = xcalloc (1, sizeof (*v)); | |
180 | v->key = xstrdup (string); | |
181 | } | |
182 | return *e; | |
94ca3aab | 183 | } |
184 | \f | |
185 | /* Stack code. */ | |
186 | ||
187 | struct symbol_stack_entry | |
188 | { | |
189 | symbol *value; | |
190 | struct symbol_stack_entry *next; | |
191 | }; | |
192 | struct obstack symbol_stack_obstack; | |
193 | struct symbol_stack_entry *symbol_stack; | |
194 | ||
195 | struct file_stack_entry | |
196 | { | |
197 | file *value; | |
198 | struct file_stack_entry *next; | |
199 | }; | |
200 | struct obstack file_stack_obstack; | |
201 | struct file_stack_entry *file_stack; | |
202 | ||
203 | static void | |
204 | symbol_push (p) | |
205 | symbol *p; | |
206 | { | |
207 | struct symbol_stack_entry *ep = (struct symbol_stack_entry *) obstack_alloc | |
208 | (&symbol_stack_obstack, sizeof (struct symbol_stack_entry)); | |
209 | ep->value = p; | |
210 | ep->next = symbol_stack; | |
211 | symbol_stack = ep; | |
212 | } | |
213 | ||
214 | static symbol * | |
215 | symbol_pop () | |
216 | { | |
217 | struct symbol_stack_entry *ep = symbol_stack; | |
218 | symbol *p; | |
219 | if (ep == NULL) | |
220 | return NULL; | |
221 | p = ep->value; | |
222 | symbol_stack = ep->next; | |
223 | obstack_free (&symbol_stack_obstack, ep); | |
224 | return p; | |
225 | } | |
226 | ||
227 | static void | |
228 | file_push (p) | |
229 | file *p; | |
230 | { | |
231 | struct file_stack_entry *ep; | |
232 | ||
233 | if (p->tweaking) | |
234 | return; | |
235 | ||
236 | ep = (struct file_stack_entry *) obstack_alloc | |
237 | (&file_stack_obstack, sizeof (struct file_stack_entry)); | |
238 | ep->value = p; | |
239 | ep->next = file_stack; | |
240 | file_stack = ep; | |
241 | p->tweaking = 1; | |
242 | } | |
243 | ||
244 | static file * | |
245 | file_pop () | |
246 | { | |
247 | struct file_stack_entry *ep = file_stack; | |
248 | file *p; | |
249 | if (ep == NULL) | |
250 | return NULL; | |
251 | p = ep->value; | |
252 | file_stack = ep->next; | |
253 | obstack_free (&file_stack_obstack, ep); | |
254 | p->tweaking = 0; | |
255 | return p; | |
256 | } | |
257 | \f | |
258 | /* Other machinery. */ | |
259 | ||
56e06438 | 260 | /* Initialize the tlink machinery. Called from do_tlink. */ |
261 | ||
94ca3aab | 262 | static void |
263 | tlink_init () | |
264 | { | |
e504db4a | 265 | const char *p; |
94ca3aab | 266 | |
1f3233d1 | 267 | symbol_table = htab_create (500, hash_string_hash, hash_string_eq, |
268 | NULL); | |
269 | file_table = htab_create (500, hash_string_hash, hash_string_eq, | |
270 | NULL); | |
271 | demangled_table = htab_create (500, hash_string_hash, hash_string_eq, | |
272 | NULL); | |
273 | ||
94ca3aab | 274 | obstack_begin (&symbol_stack_obstack, 0); |
275 | obstack_begin (&file_stack_obstack, 0); | |
276 | ||
277 | p = getenv ("TLINK_VERBOSE"); | |
278 | if (p) | |
279 | tlink_verbose = atoi (p); | |
280 | else | |
281 | { | |
282 | tlink_verbose = 1; | |
283 | if (vflag) | |
284 | tlink_verbose = 2; | |
285 | if (debug) | |
286 | tlink_verbose = 3; | |
287 | } | |
288 | } | |
289 | ||
290 | static int | |
291 | tlink_execute (prog, argv, redir) | |
e504db4a | 292 | const char *prog; |
94ca3aab | 293 | char **argv; |
e504db4a | 294 | const char *redir; |
94ca3aab | 295 | { |
296 | collect_execute (prog, argv, redir); | |
297 | return collect_wait (prog); | |
40570cc2 | 298 | } |
94ca3aab | 299 | |
300 | static char * | |
301 | frob_extension (s, ext) | |
e504db4a | 302 | const char *s; |
0809af09 | 303 | const char *ext; |
94ca3aab | 304 | { |
78dbff7c | 305 | const char *p = strrchr (s, '/'); |
94ca3aab | 306 | if (! p) |
307 | p = s; | |
78dbff7c | 308 | p = strrchr (p, '.'); |
94ca3aab | 309 | if (! p) |
310 | p = s + strlen (s); | |
311 | ||
312 | obstack_grow (&temporary_obstack, s, p - s); | |
313 | return obstack_copy0 (&temporary_obstack, ext, strlen (ext)); | |
314 | } | |
315 | ||
316 | static char * | |
317 | obstack_fgets (stream, ob) | |
318 | FILE *stream; | |
319 | struct obstack *ob; | |
320 | { | |
321 | int c; | |
322 | while ((c = getc (stream)) != EOF && c != '\n') | |
323 | obstack_1grow (ob, c); | |
324 | if (obstack_object_size (ob) == 0) | |
325 | return NULL; | |
326 | obstack_1grow (ob, '\0'); | |
327 | return obstack_finish (ob); | |
328 | } | |
329 | ||
330 | static char * | |
331 | tfgets (stream) | |
332 | FILE *stream; | |
333 | { | |
334 | return obstack_fgets (stream, &temporary_obstack); | |
335 | } | |
336 | ||
337 | static char * | |
338 | pfgets (stream) | |
339 | FILE *stream; | |
340 | { | |
341 | return obstack_fgets (stream, &permanent_obstack); | |
342 | } | |
343 | \f | |
344 | /* Real tlink code. */ | |
345 | ||
56e06438 | 346 | /* Subroutine of read_repo_file. We are reading the repo file for file F, |
347 | which is coming in on STREAM, and the symbol that comes next in STREAM | |
348 | is offerred, chosen or provided if CHOSEN is 0, 1 or 2, respectively. | |
349 | ||
350 | XXX "provided" is unimplemented, both here and in the compiler. */ | |
351 | ||
94ca3aab | 352 | static void |
353 | freadsym (stream, f, chosen) | |
354 | FILE *stream; | |
355 | file *f; | |
356 | int chosen; | |
357 | { | |
358 | symbol *sym; | |
359 | ||
360 | { | |
e504db4a | 361 | const char *name = tfgets (stream); |
94ca3aab | 362 | sym = symbol_hash_lookup (name, true); |
363 | } | |
364 | ||
365 | if (sym->file == NULL) | |
366 | { | |
56e06438 | 367 | /* We didn't have this symbol already, so we choose this file. */ |
368 | ||
94ca3aab | 369 | symbol_push (sym); |
370 | sym->file = f; | |
371 | sym->chosen = chosen; | |
372 | } | |
373 | else if (chosen) | |
374 | { | |
56e06438 | 375 | /* We want this file; cast aside any pretender. */ |
376 | ||
94ca3aab | 377 | if (sym->chosen && sym->file != f) |
378 | { | |
379 | if (sym->chosen == 1) | |
380 | file_push (sym->file); | |
381 | else | |
382 | { | |
383 | file_push (f); | |
384 | f = sym->file; | |
385 | chosen = sym->chosen; | |
386 | } | |
387 | } | |
388 | sym->file = f; | |
389 | sym->chosen = chosen; | |
390 | } | |
391 | } | |
392 | ||
56e06438 | 393 | /* Read in the repo file denoted by F, and record all its information. */ |
394 | ||
94ca3aab | 395 | static void |
396 | read_repo_file (f) | |
397 | file *f; | |
398 | { | |
399 | char c; | |
1f3233d1 | 400 | FILE *stream = fopen (f->key, "r"); |
94ca3aab | 401 | |
402 | if (tlink_verbose >= 2) | |
1f3233d1 | 403 | fprintf (stderr, _("collect: reading %s\n"), f->key); |
94ca3aab | 404 | |
405 | while (fscanf (stream, "%c ", &c) == 1) | |
406 | { | |
407 | switch (c) | |
408 | { | |
409 | case 'A': | |
410 | f->args = pfgets (stream); | |
411 | break; | |
412 | case 'D': | |
413 | f->dir = pfgets (stream); | |
414 | break; | |
415 | case 'M': | |
416 | f->main = pfgets (stream); | |
417 | break; | |
418 | case 'P': | |
419 | freadsym (stream, f, 2); | |
420 | break; | |
421 | case 'C': | |
422 | freadsym (stream, f, 1); | |
423 | break; | |
424 | case 'O': | |
425 | freadsym (stream, f, 0); | |
426 | break; | |
427 | } | |
428 | obstack_free (&temporary_obstack, temporary_firstobj); | |
429 | } | |
430 | fclose (stream); | |
431 | if (f->args == NULL) | |
432 | f->args = getenv ("COLLECT_GCC_OPTIONS"); | |
433 | if (f->dir == NULL) | |
434 | f->dir = "."; | |
435 | } | |
436 | ||
56e06438 | 437 | /* We might want to modify LINE, which is a symbol line from file F. We do |
438 | this if either we saw an error message referring to the symbol in | |
439 | question, or we have already allocated the symbol to another file and | |
440 | this one wants to emit it as well. */ | |
441 | ||
94ca3aab | 442 | static void |
443 | maybe_tweak (line, f) | |
444 | char *line; | |
445 | file *f; | |
446 | { | |
447 | symbol *sym = symbol_hash_lookup (line + 2, false); | |
448 | ||
449 | if ((sym->file == f && sym->tweaking) | |
450 | || (sym->file != f && line[0] == 'C')) | |
451 | { | |
452 | sym->tweaking = 0; | |
453 | sym->tweaked = 1; | |
454 | ||
455 | if (line[0] == 'O') | |
456 | line[0] = 'C'; | |
457 | else | |
458 | line[0] = 'O'; | |
459 | } | |
460 | } | |
461 | ||
56e06438 | 462 | /* Update the repo files for each of the object files we have adjusted and |
463 | recompile. | |
464 | ||
465 | XXX Should this use collect_execute instead of system? */ | |
466 | ||
94ca3aab | 467 | static int |
468 | recompile_files () | |
469 | { | |
470 | file *f; | |
471 | ||
db62533f | 472 | putenv (xstrdup ("COMPILER_PATH")); |
473 | putenv (xstrdup ("LIBRARY_PATH")); | |
40570cc2 | 474 | |
94ca3aab | 475 | while ((f = file_pop ()) != NULL) |
476 | { | |
477 | char *line, *command; | |
1f3233d1 | 478 | FILE *stream = fopen (f->key, "r"); |
479 | const char *const outname = frob_extension (f->key, ".rnw"); | |
94ca3aab | 480 | FILE *output = fopen (outname, "w"); |
481 | ||
482 | while ((line = tfgets (stream)) != NULL) | |
483 | { | |
484 | switch (line[0]) | |
485 | { | |
486 | case 'C': | |
487 | case 'O': | |
488 | maybe_tweak (line, f); | |
489 | } | |
490 | fprintf (output, "%s\n", line); | |
491 | } | |
492 | fclose (stream); | |
493 | fclose (output); | |
1f3233d1 | 494 | rename (outname, f->key); |
94ca3aab | 495 | |
496 | obstack_grow (&temporary_obstack, "cd ", 3); | |
497 | obstack_grow (&temporary_obstack, f->dir, strlen (f->dir)); | |
498 | obstack_grow (&temporary_obstack, "; ", 2); | |
499 | obstack_grow (&temporary_obstack, c_file_name, strlen (c_file_name)); | |
500 | obstack_1grow (&temporary_obstack, ' '); | |
501 | obstack_grow (&temporary_obstack, f->args, strlen (f->args)); | |
502 | obstack_1grow (&temporary_obstack, ' '); | |
503 | command = obstack_copy0 (&temporary_obstack, f->main, strlen (f->main)); | |
504 | ||
505 | if (tlink_verbose) | |
a4db0a1d | 506 | fprintf (stderr, _("collect: recompiling %s\n"), f->main); |
94ca3aab | 507 | if (tlink_verbose >= 3) |
508 | fprintf (stderr, "%s\n", command); | |
509 | ||
510 | if (system (command) != 0) | |
511 | return 0; | |
512 | ||
513 | read_repo_file (f); | |
514 | ||
515 | obstack_free (&temporary_obstack, temporary_firstobj); | |
516 | } | |
517 | return 1; | |
518 | } | |
519 | ||
56e06438 | 520 | /* The first phase of processing: determine which object files have |
521 | .rpo files associated with them, and read in the information. */ | |
522 | ||
94ca3aab | 523 | static int |
524 | read_repo_files (object_lst) | |
525 | char **object_lst; | |
526 | { | |
527 | char **object = object_lst; | |
528 | ||
529 | for (; *object; object++) | |
530 | { | |
d823001a | 531 | const char *p; |
94ca3aab | 532 | file *f; |
533 | ||
d823001a | 534 | /* Don't bother trying for ld flags. */ |
535 | if (*object[0] == '-') | |
536 | continue; | |
537 | ||
538 | p = frob_extension (*object, ".rpo"); | |
539 | ||
94ca3aab | 540 | if (! file_exists (p)) |
541 | continue; | |
542 | ||
543 | f = file_hash_lookup (p); | |
544 | ||
545 | read_repo_file (f); | |
546 | } | |
547 | ||
548 | if (file_stack != NULL && ! recompile_files ()) | |
549 | return 0; | |
550 | ||
551 | return (symbol_stack != NULL); | |
552 | } | |
553 | ||
56e06438 | 554 | /* Add the demangled forms of any new symbols to the hash table. */ |
555 | ||
94ca3aab | 556 | static void |
557 | demangle_new_symbols () | |
558 | { | |
559 | symbol *sym; | |
560 | ||
561 | while ((sym = symbol_pop ()) != NULL) | |
562 | { | |
563 | demangled *dem; | |
1f3233d1 | 564 | const char *p = cplus_demangle (sym->key, DMGL_PARAMS | DMGL_ANSI); |
94ca3aab | 565 | |
566 | if (! p) | |
567 | continue; | |
568 | ||
569 | dem = demangled_hash_lookup (p, true); | |
1f3233d1 | 570 | dem->mangled = sym->key; |
94ca3aab | 571 | } |
572 | } | |
573 | ||
56e06438 | 574 | /* Step through the output of the linker, in the file named FNAME, and |
575 | adjust the settings for each symbol encountered. */ | |
576 | ||
94ca3aab | 577 | static int |
578 | scan_linker_output (fname) | |
0809af09 | 579 | const char *fname; |
94ca3aab | 580 | { |
581 | FILE *stream = fopen (fname, "r"); | |
582 | char *line; | |
583 | ||
584 | while ((line = tfgets (stream)) != NULL) | |
585 | { | |
586 | char *p = line, *q; | |
587 | symbol *sym; | |
588 | int end; | |
40570cc2 | 589 | |
ba1c8484 | 590 | while (*p && ISSPACE ((unsigned char)*p)) |
94ca3aab | 591 | ++p; |
592 | ||
593 | if (! *p) | |
594 | continue; | |
595 | ||
ba1c8484 | 596 | for (q = p; *q && ! ISSPACE ((unsigned char)*q); ++q) |
94ca3aab | 597 | ; |
598 | ||
599 | /* Try the first word on the line. */ | |
600 | if (*p == '.') | |
601 | ++p; | |
602 | if (*p == '_' && prepends_underscore) | |
603 | ++p; | |
604 | ||
605 | end = ! *q; | |
606 | *q = 0; | |
607 | sym = symbol_hash_lookup (p, false); | |
608 | ||
7234ad38 | 609 | /* Some SVR4 linkers produce messages like |
610 | ld: 0711-317 ERROR: Undefined symbol: .g__t3foo1Zi | |
611 | */ | |
612 | if (! sym && ! end && strstr (q+1, "Undefined symbol: ")) | |
613 | { | |
614 | char *p = strrchr (q+1, ' '); | |
615 | p++; | |
616 | if (*p == '.') | |
617 | p++; | |
618 | if (*p == '_' && prepends_underscore) | |
619 | p++; | |
620 | sym = symbol_hash_lookup (p, false); | |
621 | } | |
622 | ||
94ca3aab | 623 | if (! sym && ! end) |
bd855dab | 624 | /* Try a mangled name in quotes. */ |
94ca3aab | 625 | { |
e504db4a | 626 | const char *oldq = q+1; |
94ca3aab | 627 | demangled *dem = 0; |
94ca3aab | 628 | q = 0; |
629 | ||
bd855dab | 630 | /* First try `GNU style'. */ |
78dbff7c | 631 | p = strchr (oldq, '`'); |
bd855dab | 632 | if (p) |
78dbff7c | 633 | p++, q = strchr (p, '\''); |
bd855dab | 634 | /* Then try "double quotes". */ |
78dbff7c | 635 | else if (p = strchr (oldq, '"'), p) |
636 | p++, q = strchr (p, '"'); | |
94ca3aab | 637 | |
53bdb86c | 638 | /* Don't let the strstr's below see the demangled name; we |
639 | might get spurious matches. */ | |
640 | if (p) | |
641 | p[-1] = '\0'; | |
642 | ||
b51e1cf8 | 643 | /* We need to check for certain error keywords here, or we would |
644 | mistakenly use GNU ld's "In function `foo':" message. */ | |
645 | if (q && (strstr (oldq, "ndefined") | |
13d09b16 | 646 | || strstr (oldq, "nresolved") |
036a9f3c | 647 | || strstr (oldq, "nsatisfied") |
b51e1cf8 | 648 | || strstr (oldq, "ultiple"))) |
94ca3aab | 649 | { |
bd855dab | 650 | *q = 0; |
651 | dem = demangled_hash_lookup (p, false); | |
652 | if (dem) | |
653 | sym = symbol_hash_lookup (dem->mangled, false); | |
654 | else | |
40570cc2 | 655 | { |
656 | if (*p == '_' && prepends_underscore) | |
01e2144f | 657 | ++p; |
658 | sym = symbol_hash_lookup (p, false); | |
659 | } | |
94ca3aab | 660 | } |
94ca3aab | 661 | } |
662 | ||
663 | if (sym && sym->tweaked) | |
30c1e454 | 664 | { |
665 | fclose (stream); | |
666 | return 0; | |
667 | } | |
94ca3aab | 668 | if (sym && !sym->tweaking) |
669 | { | |
670 | if (tlink_verbose >= 2) | |
a4db0a1d | 671 | fprintf (stderr, _("collect: tweaking %s in %s\n"), |
1f3233d1 | 672 | sym->key, sym->file->key); |
94ca3aab | 673 | sym->tweaking = 1; |
674 | file_push (sym->file); | |
675 | } | |
40570cc2 | 676 | |
94ca3aab | 677 | obstack_free (&temporary_obstack, temporary_firstobj); |
678 | } | |
679 | ||
30c1e454 | 680 | fclose (stream); |
94ca3aab | 681 | return (file_stack != NULL); |
682 | } | |
683 | ||
56e06438 | 684 | /* Entry point for tlink. Called from main in collect2.c. |
685 | ||
686 | Iteratively try to provide definitions for all the unresolved symbols | |
687 | mentioned in the linker error messages. | |
688 | ||
689 | LD_ARGV is an array of arguments for the linker. | |
690 | OBJECT_LST is an array of object files that we may be able to recompile | |
691 | to provide missing definitions. Currently ignored. */ | |
692 | ||
94ca3aab | 693 | void |
694 | do_tlink (ld_argv, object_lst) | |
e504db4a | 695 | char **ld_argv, **object_lst ATTRIBUTE_UNUSED; |
94ca3aab | 696 | { |
697 | int exit = tlink_execute ("ld", ld_argv, ldout); | |
698 | ||
699 | tlink_init (); | |
700 | ||
701 | if (exit) | |
702 | { | |
703 | int i = 0; | |
704 | ||
705 | /* Until collect does a better job of figuring out which are object | |
706 | files, assume that everything on the command line could be. */ | |
707 | if (read_repo_files (ld_argv)) | |
708 | while (exit && i++ < MAX_ITERATIONS) | |
709 | { | |
710 | if (tlink_verbose >= 3) | |
711 | dump_file (ldout); | |
712 | demangle_new_symbols (); | |
713 | if (! scan_linker_output (ldout)) | |
714 | break; | |
715 | if (! recompile_files ()) | |
716 | break; | |
717 | if (tlink_verbose) | |
a4db0a1d | 718 | fprintf (stderr, _("collect: relinking\n")); |
94ca3aab | 719 | exit = tlink_execute ("ld", ld_argv, ldout); |
720 | } | |
721 | } | |
722 | ||
723 | dump_file (ldout); | |
724 | unlink (ldout); | |
725 | if (exit) | |
726 | { | |
727 | error ("ld returned %d exit status", exit); | |
728 | collect_exit (exit); | |
729 | } | |
730 | } |