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