]>
Commit | Line | Data |
---|---|---|
d7f09764 DN |
1 | /* LTO plugin for gold. |
2 | Copyright (C) 2009 Free Software Foundation, Inc. | |
3 | Contributed by Rafael Avila de Espindola (espindola@google.com). | |
4 | ||
5 | This program is free software; you can redistribute it and/or modify | |
6 | it under the terms of the GNU General Public License as published by | |
7 | the Free Software Foundation; either version 3, or (at your option) | |
8 | any later version. | |
9 | ||
10 | This program is distributed in the hope that it will be useful, but | |
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU General Public License | |
16 | along with this program; see the file COPYING3. If not see | |
17 | <http://www.gnu.org/licenses/>. */ | |
18 | ||
19 | /* The plugin has only one external function: onload. Gold passes it an array of | |
20 | function that the plugin uses to communicate back to gold. | |
21 | ||
22 | With the functions provided by gold, the plugin can be notified when | |
23 | gold first analyzes a file and pass a symbol table back to gold. The plugin | |
24 | is also notified when all symbols have been read and it is time to generate | |
25 | machine code for the necessary symbols. | |
26 | ||
27 | More information at http://gcc.gnu.org/wiki/whopr/driver. | |
28 | ||
29 | This plugin should be passed the lto-wrapper options and will forward them. | |
30 | It also has 2 options of its own: | |
31 | -debug: Print the command line used to run lto-wrapper. | |
32 | -nop: Instead of running lto-wrapper, pass the original to the plugin. This | |
33 | only works if the input files are hybrid. */ | |
34 | ||
35 | #include <assert.h> | |
36 | #include <string.h> | |
37 | #include <stdlib.h> | |
38 | #include <stdio.h> | |
39 | #include <inttypes.h> | |
d7f09764 DN |
40 | #include <sys/stat.h> |
41 | #include <unistd.h> | |
42 | #include <fcntl.h> | |
43 | #include <sys/types.h> | |
44 | #include <sys/wait.h> | |
45 | #include <stdbool.h> | |
46 | #include <libiberty.h> | |
47 | ||
48 | /* The presence of gelf.h is checked by the toplevel configure script. */ | |
49 | #include <gelf.h> | |
50 | ||
51 | #include "plugin-api.h" | |
52 | #include "../gcc/lto/common.h" | |
53 | ||
54 | /* The part of the symbol table the plugin has to keep track of. Note that we | |
55 | must keep SYMS until all_symbols_read is called to give the linker time to | |
56 | copy the symbol information. */ | |
57 | ||
58 | struct plugin_symtab | |
59 | { | |
60 | int nsyms; | |
61 | uint32_t *slots; | |
62 | struct ld_plugin_symbol *syms; | |
63 | }; | |
64 | ||
65 | /* All that we have to remember about a file. */ | |
66 | ||
67 | struct plugin_file_info | |
68 | { | |
69 | char *name; | |
70 | void *handle; | |
71 | struct plugin_symtab symtab; | |
d7f09764 DN |
72 | }; |
73 | ||
74 | ||
94086ef6 | 75 | static char *arguments_file_name; |
d7f09764 DN |
76 | static ld_plugin_register_claim_file register_claim_file; |
77 | static ld_plugin_add_symbols add_symbols; | |
78 | static ld_plugin_register_all_symbols_read register_all_symbols_read; | |
79 | static ld_plugin_get_symbols get_symbols; | |
80 | static ld_plugin_register_cleanup register_cleanup; | |
81 | static ld_plugin_add_input_file add_input_file; | |
d520c7fb | 82 | static ld_plugin_add_input_library add_input_library; |
33662270 | 83 | static ld_plugin_message message; |
d7f09764 DN |
84 | |
85 | static struct plugin_file_info *claimed_files = NULL; | |
86 | static unsigned int num_claimed_files = 0; | |
87 | ||
88 | static char **output_files = NULL; | |
89 | static unsigned int num_output_files = 0; | |
90 | ||
91 | static char **lto_wrapper_argv; | |
92 | static int lto_wrapper_num_args; | |
93 | ||
94 | static char **pass_through_items = NULL; | |
95 | static unsigned int num_pass_through_items; | |
96 | ||
97 | static bool debug; | |
98 | static bool nop; | |
b10071c5 | 99 | static char *resolution_file = NULL; |
d7f09764 | 100 | |
33662270 RAE |
101 | static void |
102 | check (bool gate, enum ld_plugin_level level, const char *text) | |
103 | { | |
104 | if (gate) | |
105 | return; | |
106 | ||
107 | if (message) | |
108 | message (level, text); | |
109 | else | |
110 | { | |
111 | /* If there is no nicer way to inform the user, fallback to stderr. */ | |
112 | fprintf (stderr, "%s\n", text); | |
113 | if (level == LDPL_FATAL) | |
114 | abort (); | |
115 | } | |
116 | } | |
117 | ||
d7f09764 DN |
118 | /* Parse an entry of the IL symbol table. The data to be parsed is pointed |
119 | by P and the result is written in ENTRY. The slot number is stored in SLOT. | |
120 | Returns the address of the next entry. */ | |
121 | ||
122 | static char * | |
123 | parse_table_entry (char *p, struct ld_plugin_symbol *entry, uint32_t *slot) | |
124 | { | |
125 | unsigned char t; | |
126 | enum ld_plugin_symbol_kind translate_kind[] = | |
127 | { | |
128 | LDPK_DEF, | |
129 | LDPK_WEAKDEF, | |
130 | LDPK_UNDEF, | |
131 | LDPK_WEAKUNDEF, | |
132 | LDPK_COMMON | |
133 | }; | |
134 | ||
135 | enum ld_plugin_symbol_visibility translate_visibility[] = | |
136 | { | |
137 | LDPV_DEFAULT, | |
138 | LDPV_PROTECTED, | |
139 | LDPV_INTERNAL, | |
140 | LDPV_HIDDEN | |
141 | }; | |
142 | ||
143 | entry->name = strdup (p); | |
144 | while (*p) | |
145 | p++; | |
146 | p++; | |
147 | ||
148 | entry->version = NULL; | |
149 | ||
150 | entry->comdat_key = p; | |
151 | while (*p) | |
152 | p++; | |
153 | p++; | |
154 | ||
155 | if (strlen (entry->comdat_key) == 0) | |
156 | entry->comdat_key = NULL; | |
157 | else | |
158 | entry->comdat_key = strdup (entry->comdat_key); | |
159 | ||
160 | t = *p; | |
33662270 | 161 | check (t <= 4, LDPL_FATAL, "invalid symbol kind found"); |
d7f09764 DN |
162 | entry->def = translate_kind[t]; |
163 | p++; | |
164 | ||
165 | t = *p; | |
33662270 | 166 | check (t <= 3, LDPL_FATAL, "invalid symbol visibility found"); |
d7f09764 DN |
167 | entry->visibility = translate_visibility[t]; |
168 | p++; | |
169 | ||
170 | entry->size = *(uint64_t *) p; | |
171 | p += 8; | |
172 | ||
173 | *slot = *(uint32_t *) p; | |
174 | p += 4; | |
175 | ||
176 | entry->resolution = LDPR_UNKNOWN; | |
177 | ||
178 | return p; | |
179 | } | |
180 | ||
181 | /* Return the section in ELF that is named NAME. */ | |
182 | ||
183 | static Elf_Scn * | |
184 | get_section (Elf *elf, const char *name) | |
185 | { | |
186 | Elf_Scn *section = 0; | |
187 | GElf_Ehdr header; | |
188 | GElf_Ehdr *t = gelf_getehdr (elf, &header); | |
189 | if (t == NULL) | |
190 | return NULL; | |
191 | assert (t == &header); | |
192 | ||
193 | while ((section = elf_nextscn(elf, section)) != 0) | |
194 | { | |
195 | GElf_Shdr shdr; | |
196 | GElf_Shdr *tshdr = gelf_getshdr (section, &shdr); | |
197 | const char *t; | |
198 | assert (tshdr == &shdr); | |
199 | t = elf_strptr (elf, header.e_shstrndx, shdr.sh_name); | |
200 | assert (t != NULL); | |
201 | if (strcmp (t, name) == 0) | |
202 | return section; | |
203 | } | |
204 | return NULL; | |
205 | } | |
206 | ||
207 | /* Returns the IL symbol table of file ELF. */ | |
208 | ||
209 | static Elf_Data * | |
210 | get_symtab (Elf *elf) | |
211 | { | |
212 | Elf_Data *data = 0; | |
213 | Elf_Scn *section = get_section (elf, ".gnu.lto_.symtab"); | |
214 | if (!section) | |
215 | return NULL; | |
216 | ||
217 | data = elf_getdata (section, data); | |
218 | assert (data); | |
219 | return data; | |
220 | } | |
221 | ||
222 | /* Translate the IL symbol table SYMTAB. Write the slots and symbols in OUT. */ | |
223 | ||
224 | static void | |
225 | translate (Elf_Data *symtab, struct plugin_symtab *out) | |
226 | { | |
227 | uint32_t *slots = NULL; | |
228 | char *data = symtab->d_buf; | |
229 | char *end = data + symtab->d_size; | |
230 | struct ld_plugin_symbol *syms = NULL; | |
231 | int n = 0; | |
232 | ||
233 | while (data < end) | |
234 | { | |
235 | n++; | |
236 | syms = realloc (syms, n * sizeof (struct ld_plugin_symbol)); | |
33662270 | 237 | check (syms, LDPL_FATAL, "could not allocate memory"); |
d7f09764 | 238 | slots = realloc (slots, n * sizeof (uint32_t)); |
33662270 | 239 | check (slots, LDPL_FATAL, "could not allocate memory"); |
d7f09764 DN |
240 | data = parse_table_entry (data, &syms[n - 1], &slots[n - 1]); |
241 | } | |
242 | ||
243 | out->nsyms = n; | |
244 | out->syms = syms; | |
245 | out->slots = slots; | |
246 | } | |
247 | ||
b10071c5 RAE |
248 | /* Free all memory that is no longer needed after writing the symbol |
249 | resolution. */ | |
d7f09764 DN |
250 | |
251 | static void | |
252 | free_1 (void) | |
253 | { | |
254 | unsigned int i; | |
255 | for (i = 0; i < num_claimed_files; i++) | |
256 | { | |
257 | struct plugin_file_info *info = &claimed_files[i]; | |
258 | struct plugin_symtab *symtab = &info->symtab; | |
259 | unsigned int j; | |
260 | for (j = 0; j < symtab->nsyms; j++) | |
261 | { | |
262 | struct ld_plugin_symbol *s = &symtab->syms[j]; | |
263 | free (s->name); | |
264 | if (s->comdat_key) | |
265 | free (s->comdat_key); | |
266 | } | |
267 | free (symtab->syms); | |
268 | symtab->syms = NULL; | |
269 | } | |
270 | } | |
271 | ||
272 | /* Free all remaining memory. */ | |
273 | ||
274 | static void | |
275 | free_2 (void) | |
276 | { | |
277 | unsigned int i; | |
278 | for (i = 0; i < num_claimed_files; i++) | |
279 | { | |
280 | struct plugin_file_info *info = &claimed_files[i]; | |
281 | struct plugin_symtab *symtab = &info->symtab; | |
282 | free (symtab->slots); | |
283 | free (info->name); | |
284 | } | |
285 | ||
286 | for (i = 0; i < num_output_files; i++) | |
287 | free (output_files[i]); | |
288 | free (output_files); | |
289 | ||
290 | free (claimed_files); | |
291 | claimed_files = NULL; | |
292 | num_claimed_files = 0; | |
293 | ||
94086ef6 RAE |
294 | if (arguments_file_name) |
295 | free (arguments_file_name); | |
296 | arguments_file_name = NULL; | |
b10071c5 RAE |
297 | |
298 | if (resolution_file) | |
299 | { | |
300 | free (resolution_file); | |
301 | resolution_file = NULL; | |
302 | } | |
d7f09764 DN |
303 | } |
304 | ||
305 | /* Writes the relocations to disk. */ | |
306 | ||
307 | static void | |
308 | write_resolution (void) | |
309 | { | |
310 | unsigned int i; | |
311 | FILE *f; | |
d7f09764 | 312 | |
b10071c5 | 313 | f = fopen (resolution_file, "w"); |
33662270 | 314 | check (f, LDPL_FATAL, "could not open file"); |
d7f09764 DN |
315 | |
316 | fprintf (f, "%d\n", num_claimed_files); | |
317 | ||
318 | for (i = 0; i < num_claimed_files; i++) | |
319 | { | |
320 | struct plugin_file_info *info = &claimed_files[i]; | |
321 | struct plugin_symtab *symtab = &info->symtab; | |
b10071c5 | 322 | struct ld_plugin_symbol *syms = symtab->syms; |
d7f09764 DN |
323 | unsigned j; |
324 | ||
325 | assert (syms); | |
326 | get_symbols (info->handle, symtab->nsyms, syms); | |
327 | ||
328 | fprintf (f, "%s %d\n", info->name, info->symtab.nsyms); | |
329 | ||
330 | for (j = 0; j < info->symtab.nsyms; j++) | |
331 | { | |
332 | uint32_t slot = symtab->slots[j]; | |
333 | unsigned int resolution = syms[j].resolution; | |
06bd7f56 | 334 | fprintf (f, "%d %s %s\n", slot, lto_resolution_str[resolution], syms[j].name); |
d7f09764 | 335 | } |
d7f09764 DN |
336 | } |
337 | fclose (f); | |
338 | } | |
339 | ||
340 | /* Pass files generated by the lto-wrapper to the linker. FD is lto-wrapper's | |
341 | stdout. */ | |
342 | ||
343 | static void | |
344 | add_output_files (FILE *f) | |
345 | { | |
33662270 | 346 | char fname[1000]; /* FIXME: Remove this restriction. */ |
d7f09764 DN |
347 | |
348 | for (;;) | |
349 | { | |
350 | size_t len; | |
351 | char *s = fgets (fname, sizeof (fname), f); | |
352 | if (!s) | |
353 | break; | |
354 | ||
355 | len = strlen (s); | |
33662270 | 356 | check (s[len - 1] == '\n', LDPL_FATAL, "file name too long"); |
d7f09764 DN |
357 | s[len - 1] = '\0'; |
358 | ||
359 | num_output_files++; | |
360 | output_files = realloc (output_files, num_output_files * sizeof (char *)); | |
361 | output_files[num_output_files - 1] = strdup (s); | |
362 | add_input_file (output_files[num_output_files - 1]); | |
363 | } | |
364 | } | |
365 | ||
366 | /* Execute the lto-wrapper. ARGV[0] is the binary. The rest of ARGV is the | |
367 | argument list. */ | |
368 | ||
369 | static void | |
370 | exec_lto_wrapper (char *argv[]) | |
371 | { | |
372 | int t; | |
373 | int status; | |
374 | char *at_args; | |
d7f09764 DN |
375 | FILE *args; |
376 | FILE *wrapper_output; | |
377 | char *new_argv[3]; | |
378 | struct pex_obj *pex; | |
379 | const char *errmsg; | |
380 | ||
381 | /* Write argv to a file to avoid a command line that is too long. */ | |
94086ef6 RAE |
382 | arguments_file_name = make_temp_file (""); |
383 | check (arguments_file_name, LDPL_FATAL, | |
384 | "Failed to generate a temorary file name"); | |
d7f09764 | 385 | |
94086ef6 | 386 | args = fopen (arguments_file_name, "w"); |
33662270 | 387 | check (args, LDPL_FATAL, "could not open arguments file"); |
d7f09764 DN |
388 | |
389 | t = writeargv (&argv[1], args); | |
33662270 | 390 | check (t == 0, LDPL_FATAL, "could not write arguments"); |
d7f09764 | 391 | t = fclose (args); |
33662270 | 392 | check (t == 0, LDPL_FATAL, "could not close arguments file"); |
d7f09764 | 393 | |
94086ef6 RAE |
394 | at_args = concat ("@", arguments_file_name, NULL); |
395 | check (at_args, LDPL_FATAL, "could not allocate"); | |
396 | ||
d7f09764 DN |
397 | new_argv[0] = argv[0]; |
398 | new_argv[1] = at_args; | |
399 | new_argv[2] = NULL; | |
400 | ||
401 | if (debug) | |
402 | { | |
403 | int i; | |
404 | for (i = 0; new_argv[i]; i++) | |
405 | fprintf (stderr, "%s ", new_argv[i]); | |
406 | fprintf (stderr, "\n"); | |
407 | } | |
408 | ||
409 | ||
410 | pex = pex_init (PEX_USE_PIPES, "lto-wrapper", NULL); | |
33662270 | 411 | check (pex != NULL, LDPL_FATAL, "could not pex_init lto-wrapper"); |
d7f09764 DN |
412 | |
413 | errmsg = pex_run (pex, 0, new_argv[0], new_argv, NULL, NULL, &t); | |
33662270 RAE |
414 | check (errmsg == NULL, LDPL_FATAL, "could not run lto-wrapper"); |
415 | check (t == 0, LDPL_FATAL, "could not run lto-wrapper"); | |
d7f09764 DN |
416 | |
417 | wrapper_output = pex_read_output (pex, 0); | |
33662270 | 418 | check (wrapper_output, LDPL_FATAL, "could not read lto-wrapper output"); |
d7f09764 DN |
419 | |
420 | add_output_files (wrapper_output); | |
421 | ||
422 | t = pex_get_status (pex, 1, &status); | |
33662270 RAE |
423 | check (t == 1, LDPL_FATAL, "could not get lto-wrapper exit status"); |
424 | check (WIFEXITED (status) && WEXITSTATUS (status) == 0, LDPL_FATAL, | |
425 | "lto-wrapper failed"); | |
d7f09764 DN |
426 | |
427 | pex_free (pex); | |
428 | ||
d7f09764 DN |
429 | free (at_args); |
430 | } | |
431 | ||
432 | /* Pass the original files back to the linker. */ | |
433 | ||
434 | static void | |
435 | use_original_files (void) | |
436 | { | |
437 | unsigned i; | |
438 | for (i = 0; i < num_claimed_files; i++) | |
439 | { | |
440 | struct plugin_file_info *info = &claimed_files[i]; | |
441 | add_input_file (info->name); | |
442 | } | |
443 | } | |
444 | ||
445 | ||
446 | /* Called by the linker once all symbols have been read. */ | |
447 | ||
448 | static enum ld_plugin_status | |
449 | all_symbols_read_handler (void) | |
450 | { | |
451 | unsigned i; | |
06bd7f56 | 452 | unsigned num_lto_args = num_claimed_files + lto_wrapper_num_args + 2 + 1; |
d7f09764 DN |
453 | char **lto_argv; |
454 | const char **lto_arg_ptr; | |
455 | if (num_claimed_files == 0) | |
456 | return LDPS_OK; | |
457 | ||
d7f09764 DN |
458 | if (nop) |
459 | { | |
460 | use_original_files (); | |
461 | return LDPS_OK; | |
462 | } | |
463 | ||
464 | lto_argv = (char **) calloc (sizeof (char *), num_lto_args); | |
465 | lto_arg_ptr = (const char **) lto_argv; | |
466 | assert (lto_wrapper_argv); | |
467 | ||
06bd7f56 RAE |
468 | resolution_file = make_temp_file (""); |
469 | ||
d7f09764 DN |
470 | write_resolution (); |
471 | ||
b10071c5 RAE |
472 | free_1 (); |
473 | ||
d7f09764 DN |
474 | for (i = 0; i < lto_wrapper_num_args; i++) |
475 | *lto_arg_ptr++ = lto_wrapper_argv[i]; | |
476 | ||
06bd7f56 RAE |
477 | *lto_arg_ptr++ = "-fresolution"; |
478 | *lto_arg_ptr++ = resolution_file; | |
479 | ||
d7f09764 DN |
480 | for (i = 0; i < num_claimed_files; i++) |
481 | { | |
482 | struct plugin_file_info *info = &claimed_files[i]; | |
483 | ||
484 | *lto_arg_ptr++ = info->name; | |
485 | } | |
486 | ||
487 | *lto_arg_ptr++ = NULL; | |
488 | exec_lto_wrapper (lto_argv); | |
489 | ||
490 | free (lto_argv); | |
491 | ||
492 | if (pass_through_items) | |
493 | { | |
494 | unsigned int i; | |
495 | for (i = 0; i < num_pass_through_items; i++) | |
496 | { | |
d520c7fb RAE |
497 | if (strncmp (pass_through_items[i], "-l", 2) == 0) |
498 | add_input_library (pass_through_items[i] + 2); | |
499 | else | |
500 | add_input_file (pass_through_items[i]); | |
d7f09764 DN |
501 | free (pass_through_items[i]); |
502 | pass_through_items[i] = NULL; | |
503 | } | |
504 | free (pass_through_items); | |
505 | pass_through_items = NULL; | |
506 | } | |
507 | ||
508 | return LDPS_OK; | |
509 | } | |
510 | ||
511 | /* Remove temporary files at the end of the link. */ | |
512 | ||
513 | static enum ld_plugin_status | |
514 | cleanup_handler (void) | |
515 | { | |
516 | int t; | |
d7f09764 | 517 | |
1cddcdca RAE |
518 | if (debug) |
519 | return LDPS_OK; | |
520 | ||
94086ef6 | 521 | if (arguments_file_name) |
33662270 | 522 | { |
94086ef6 | 523 | t = unlink (arguments_file_name); |
aff4273c | 524 | check (t == 0, LDPL_FATAL, "could not unlink arguments file"); |
33662270 | 525 | } |
d7f09764 | 526 | |
06bd7f56 RAE |
527 | if (resolution_file) |
528 | { | |
529 | t = unlink (resolution_file); | |
530 | check (t == 0, LDPL_FATAL, "could not unlink resolution file"); | |
531 | } | |
532 | ||
d7f09764 DN |
533 | free_2 (); |
534 | return LDPS_OK; | |
535 | } | |
536 | ||
537 | /* Callback used by gold to check if the plugin will claim FILE. Writes | |
538 | the result in CLAIMED. */ | |
539 | ||
540 | static enum ld_plugin_status | |
541 | claim_file_handler (const struct ld_plugin_input_file *file, int *claimed) | |
542 | { | |
543 | enum ld_plugin_status status; | |
544 | Elf *elf; | |
545 | struct plugin_file_info lto_file; | |
546 | Elf_Data *symtab; | |
d7f09764 DN |
547 | |
548 | if (file->offset != 0) | |
549 | { | |
d7f09764 | 550 | char *objname; |
7e9dc421 RG |
551 | Elf *archive; |
552 | off_t offset; | |
553 | /* We pass the offset of the actual file, not the archive header. */ | |
92fa7608 | 554 | int t = asprintf (&objname, "%s@0x%" PRIx64, file->name, |
7e9dc421 | 555 | (int64_t) file->offset); |
33662270 | 556 | check (t >= 0, LDPL_FATAL, "asprintf failed"); |
d7f09764 | 557 | lto_file.name = objname; |
7e9dc421 RG |
558 | |
559 | archive = elf_begin (file->fd, ELF_C_READ, NULL); | |
560 | check (elf_kind (archive) == ELF_K_AR, LDPL_FATAL, | |
561 | "Not an archive and offset not 0"); | |
562 | ||
563 | /* elf_rand expects the offset to point to the ar header, not the | |
564 | object itself. Subtract the size of the ar header (60 bytes). | |
565 | We don't uses sizeof (struct ar_hd) to avoid including ar.h */ | |
566 | ||
567 | offset = file->offset - 60; | |
568 | check (offset == elf_rand (archive, offset), LDPL_FATAL, | |
569 | "could not seek in archive"); | |
570 | elf = elf_begin (file->fd, ELF_C_READ, archive); | |
571 | check (elf != NULL, LDPL_FATAL, "could not find archive member"); | |
572 | elf_end (archive); | |
d7f09764 DN |
573 | } |
574 | else | |
575 | { | |
576 | lto_file.name = strdup (file->name); | |
7e9dc421 | 577 | elf = elf_begin (file->fd, ELF_C_READ, NULL); |
d7f09764 | 578 | } |
7e9dc421 | 579 | lto_file.handle = file->handle; |
d7f09764 DN |
580 | |
581 | *claimed = 0; | |
582 | ||
583 | if (!elf) | |
584 | goto err; | |
585 | ||
586 | symtab = get_symtab (elf); | |
587 | if (!symtab) | |
588 | goto err; | |
589 | ||
590 | translate (symtab, <o_file.symtab); | |
591 | ||
592 | status = add_symbols (file->handle, lto_file.symtab.nsyms, | |
593 | lto_file.symtab.syms); | |
33662270 | 594 | check (status == LDPS_OK, LDPL_FATAL, "could not add symbols"); |
d7f09764 DN |
595 | |
596 | *claimed = 1; | |
597 | num_claimed_files++; | |
598 | claimed_files = | |
599 | realloc (claimed_files, | |
600 | num_claimed_files * sizeof (struct plugin_file_info)); | |
601 | claimed_files[num_claimed_files - 1] = lto_file; | |
602 | ||
603 | goto cleanup; | |
604 | ||
605 | err: | |
d7f09764 DN |
606 | free (lto_file.name); |
607 | ||
608 | cleanup: | |
609 | if (elf) | |
610 | elf_end (elf); | |
611 | ||
612 | return LDPS_OK; | |
613 | } | |
614 | ||
615 | /* Parse the plugin options. */ | |
616 | ||
617 | static void | |
618 | process_option (const char *option) | |
619 | { | |
620 | if (strcmp (option, "-debug") == 0) | |
621 | debug = 1; | |
622 | else if (strcmp (option, "-nop") == 0) | |
623 | nop = 1; | |
624 | else if (!strncmp (option, "-pass-through=", strlen("-pass-through="))) | |
625 | { | |
626 | num_pass_through_items++; | |
d520c7fb RAE |
627 | pass_through_items = realloc (pass_through_items, |
628 | num_pass_through_items * sizeof (char *)); | |
629 | pass_through_items[num_pass_through_items - 1] = | |
630 | strdup (option + strlen ("-pass-through=")); | |
d7f09764 DN |
631 | } |
632 | else | |
633 | { | |
634 | int size; | |
635 | lto_wrapper_num_args += 1; | |
636 | size = lto_wrapper_num_args * sizeof (char *); | |
637 | lto_wrapper_argv = (char **) realloc (lto_wrapper_argv, size); | |
638 | lto_wrapper_argv[lto_wrapper_num_args - 1] = strdup(option); | |
639 | } | |
640 | } | |
641 | ||
642 | /* Called by gold after loading the plugin. TV is the transfer vector. */ | |
643 | ||
644 | enum ld_plugin_status | |
645 | onload (struct ld_plugin_tv *tv) | |
646 | { | |
647 | struct ld_plugin_tv *p; | |
648 | enum ld_plugin_status status; | |
d7f09764 DN |
649 | |
650 | unsigned version = elf_version (EV_CURRENT); | |
33662270 | 651 | check (version != EV_NONE, LDPL_FATAL, "invalid ELF version"); |
d7f09764 DN |
652 | |
653 | p = tv; | |
654 | while (p->tv_tag) | |
655 | { | |
656 | switch (p->tv_tag) | |
657 | { | |
33662270 RAE |
658 | case LDPT_MESSAGE: |
659 | message = p->tv_u.tv_message; | |
660 | break; | |
d7f09764 DN |
661 | case LDPT_REGISTER_CLAIM_FILE_HOOK: |
662 | register_claim_file = p->tv_u.tv_register_claim_file; | |
663 | break; | |
664 | case LDPT_ADD_SYMBOLS: | |
665 | add_symbols = p->tv_u.tv_add_symbols; | |
666 | break; | |
667 | case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK: | |
668 | register_all_symbols_read = p->tv_u.tv_register_all_symbols_read; | |
669 | break; | |
670 | case LDPT_GET_SYMBOLS: | |
671 | get_symbols = p->tv_u.tv_get_symbols; | |
672 | break; | |
673 | case LDPT_REGISTER_CLEANUP_HOOK: | |
674 | register_cleanup = p->tv_u.tv_register_cleanup; | |
675 | break; | |
676 | case LDPT_ADD_INPUT_FILE: | |
677 | add_input_file = p->tv_u.tv_add_input_file; | |
678 | break; | |
d520c7fb RAE |
679 | case LDPT_ADD_INPUT_LIBRARY: |
680 | add_input_library = p->tv_u.tv_add_input_library; | |
681 | break; | |
d7f09764 DN |
682 | case LDPT_OPTION: |
683 | process_option (p->tv_u.tv_string); | |
684 | break; | |
685 | default: | |
686 | break; | |
687 | } | |
688 | p++; | |
689 | } | |
690 | ||
33662270 RAE |
691 | check (register_claim_file, LDPL_FATAL, "register_claim_file not found"); |
692 | check (add_symbols, LDPL_FATAL, "add_symbols not found"); | |
d7f09764 | 693 | status = register_claim_file (claim_file_handler); |
33662270 RAE |
694 | check (status == LDPS_OK, LDPL_FATAL, |
695 | "could not register the claim_file callback"); | |
d7f09764 DN |
696 | |
697 | if (register_cleanup) | |
698 | { | |
699 | status = register_cleanup (cleanup_handler); | |
33662270 RAE |
700 | check (status == LDPS_OK, LDPL_FATAL, |
701 | "could not register the cleanup callback"); | |
d7f09764 DN |
702 | } |
703 | ||
704 | if (register_all_symbols_read) | |
705 | { | |
33662270 | 706 | check (get_symbols, LDPL_FATAL, "get_symbols not found"); |
d7f09764 | 707 | status = register_all_symbols_read (all_symbols_read_handler); |
33662270 RAE |
708 | check (status == LDPS_OK, LDPL_FATAL, |
709 | "could not register the all_symbols_read callback"); | |
d7f09764 DN |
710 | } |
711 | ||
d7f09764 DN |
712 | return LDPS_OK; |
713 | } |