1 /* test_plugin.c -- simple linker plugin test
3 Copyright (C) 2008-2016 Free Software Foundation, Inc.
4 Written by Cary Coutant <ccoutant@google.com>.
6 This file is part of gold.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21 MA 02110-1301, USA. */
30 #include "plugin-api.h"
37 struct ld_plugin_symbol* syms;
38 struct claimed_file* next;
51 static struct claimed_file* first_claimed_file = NULL;
52 static struct claimed_file* last_claimed_file = NULL;
54 static ld_plugin_register_claim_file register_claim_file_hook = NULL;
55 static ld_plugin_register_all_symbols_read register_all_symbols_read_hook = NULL;
56 static ld_plugin_register_cleanup register_cleanup_hook = NULL;
57 static ld_plugin_add_symbols add_symbols = NULL;
58 static ld_plugin_get_symbols get_symbols = NULL;
59 static ld_plugin_get_symbols get_symbols_v2 = NULL;
60 static ld_plugin_add_input_file add_input_file = NULL;
61 static ld_plugin_message message = NULL;
62 static ld_plugin_get_input_file get_input_file = NULL;
63 static ld_plugin_release_input_file release_input_file = NULL;
64 static ld_plugin_get_input_section_count get_input_section_count = NULL;
65 static ld_plugin_get_input_section_type get_input_section_type = NULL;
66 static ld_plugin_get_input_section_name get_input_section_name = NULL;
67 static ld_plugin_get_input_section_contents get_input_section_contents = NULL;
68 static ld_plugin_update_section_order update_section_order = NULL;
69 static ld_plugin_allow_section_ordering allow_section_ordering = NULL;
73 static const char *opts[MAXOPTS];
76 enum ld_plugin_status onload(struct ld_plugin_tv *tv);
77 enum ld_plugin_status claim_file_hook(const struct ld_plugin_input_file *file,
79 enum ld_plugin_status all_symbols_read_hook(void);
80 enum ld_plugin_status cleanup_hook(void);
82 static void parse_readelf_line(char*, struct sym_info*);
85 onload(struct ld_plugin_tv *tv)
87 struct ld_plugin_tv *entry;
92 for (entry = tv; entry->tv_tag != LDPT_NULL; ++entry)
94 switch (entry->tv_tag)
96 case LDPT_API_VERSION:
97 api_version = entry->tv_u.tv_val;
99 case LDPT_GOLD_VERSION:
100 gold_version = entry->tv_u.tv_val;
102 case LDPT_LINKER_OUTPUT:
106 opts[nopts++] = entry->tv_u.tv_string;
108 case LDPT_REGISTER_CLAIM_FILE_HOOK:
109 register_claim_file_hook = entry->tv_u.tv_register_claim_file;
111 case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK:
112 register_all_symbols_read_hook =
113 entry->tv_u.tv_register_all_symbols_read;
115 case LDPT_REGISTER_CLEANUP_HOOK:
116 register_cleanup_hook = entry->tv_u.tv_register_cleanup;
118 case LDPT_ADD_SYMBOLS:
119 add_symbols = entry->tv_u.tv_add_symbols;
121 case LDPT_GET_SYMBOLS:
122 get_symbols = entry->tv_u.tv_get_symbols;
124 case LDPT_GET_SYMBOLS_V2:
125 get_symbols_v2 = entry->tv_u.tv_get_symbols;
127 case LDPT_ADD_INPUT_FILE:
128 add_input_file = entry->tv_u.tv_add_input_file;
131 message = entry->tv_u.tv_message;
133 case LDPT_GET_INPUT_FILE:
134 get_input_file = entry->tv_u.tv_get_input_file;
136 case LDPT_RELEASE_INPUT_FILE:
137 release_input_file = entry->tv_u.tv_release_input_file;
139 case LDPT_GET_INPUT_SECTION_COUNT:
140 get_input_section_count = *entry->tv_u.tv_get_input_section_count;
142 case LDPT_GET_INPUT_SECTION_TYPE:
143 get_input_section_type = *entry->tv_u.tv_get_input_section_type;
145 case LDPT_GET_INPUT_SECTION_NAME:
146 get_input_section_name = *entry->tv_u.tv_get_input_section_name;
148 case LDPT_GET_INPUT_SECTION_CONTENTS:
149 get_input_section_contents = *entry->tv_u.tv_get_input_section_contents;
151 case LDPT_UPDATE_SECTION_ORDER:
152 update_section_order = *entry->tv_u.tv_update_section_order;
154 case LDPT_ALLOW_SECTION_ORDERING:
155 allow_section_ordering = *entry->tv_u.tv_allow_section_ordering;
164 fprintf(stderr, "tv_message interface missing\n");
168 if (register_claim_file_hook == NULL)
170 fprintf(stderr, "tv_register_claim_file_hook interface missing\n");
174 if (register_all_symbols_read_hook == NULL)
176 fprintf(stderr, "tv_register_all_symbols_read_hook interface missing\n");
180 if (register_cleanup_hook == NULL)
182 fprintf(stderr, "tv_register_cleanup_hook interface missing\n");
186 (*message)(LDPL_INFO, "API version: %d", api_version);
187 (*message)(LDPL_INFO, "gold version: %d", gold_version);
189 for (i = 0; i < nopts; ++i)
190 (*message)(LDPL_INFO, "option: %s", opts[i]);
192 if ((*register_claim_file_hook)(claim_file_hook) != LDPS_OK)
194 (*message)(LDPL_ERROR, "error registering claim file hook");
198 if ((*register_all_symbols_read_hook)(all_symbols_read_hook) != LDPS_OK)
200 (*message)(LDPL_ERROR, "error registering all symbols read hook");
204 if ((*register_cleanup_hook)(cleanup_hook) != LDPS_OK)
206 (*message)(LDPL_ERROR, "error registering cleanup hook");
210 if (get_input_section_count == NULL)
212 fprintf(stderr, "tv_get_input_section_count interface missing\n");
216 if (get_input_section_type == NULL)
218 fprintf(stderr, "tv_get_input_section_type interface missing\n");
222 if (get_input_section_name == NULL)
224 fprintf(stderr, "tv_get_input_section_name interface missing\n");
228 if (get_input_section_contents == NULL)
230 fprintf(stderr, "tv_get_input_section_contents interface missing\n");
234 if (update_section_order == NULL)
236 fprintf(stderr, "tv_update_section_order interface missing\n");
240 if (allow_section_ordering == NULL)
242 fprintf(stderr, "tv_allow_section_ordering interface missing\n");
249 enum ld_plugin_status
250 claim_file_hook (const struct ld_plugin_input_file* file, int* claimed)
255 struct claimed_file* claimed_file;
256 struct ld_plugin_symbol* syms;
260 struct sym_info info;
266 int irfile_was_opened = 0;
269 (*message)(LDPL_INFO,
270 "%s: claim file hook called (offset = %ld, size = %ld)",
271 file->name, (long)file->offset, (long)file->filesize);
273 /* Look for matching syms file for an archive member. */
274 if (file->offset == 0)
275 snprintf(syms_name, sizeof(syms_name), "%s.syms", file->name);
277 snprintf(syms_name, sizeof(syms_name), "%s-%d.syms",
278 file->name, (int)file->offset);
279 irfile = fopen(syms_name, "r");
282 irfile_was_opened = 1;
283 end_offset = 1 << 20;
286 /* Otherwise, see if the file itself is a syms file. */
287 if (!irfile_was_opened)
289 irfile = fdopen(file->fd, "r");
290 (void)fseek(irfile, file->offset, SEEK_SET);
291 end_offset = file->offset + file->filesize;
294 /* Look for the beginning of output from readelf -s. */
295 len = fread(buf, 1, 13, irfile);
296 if (len < 13 || strncmp(buf, "\nSymbol table", 13) != 0)
299 /* Skip the two header lines. */
300 (void) fgets(buf, sizeof(buf), irfile);
301 (void) fgets(buf, sizeof(buf), irfile);
303 if (add_symbols == NULL)
305 fprintf(stderr, "tv_add_symbols interface missing\n");
309 /* Parse the output from readelf. The columns are:
310 Index Value Size Type Binding Visibility Section Name. */
311 syms = (struct ld_plugin_symbol*)malloc(sizeof(struct ld_plugin_symbol) * 8);
315 while (ftell(irfile) < end_offset
316 && fgets(buf, sizeof(buf), irfile) != NULL)
318 parse_readelf_line(buf, &info);
320 /* Ignore local symbols. */
321 if (strncmp(info.bind, "LOCAL", 5) == 0)
324 weak = strncmp(info.bind, "WEAK", 4) == 0;
325 if (strncmp(info.sect, "UND", 3) == 0)
326 def = weak ? LDPK_WEAKUNDEF : LDPK_UNDEF;
327 else if (strncmp(info.sect, "COM", 3) == 0)
330 def = weak ? LDPK_WEAKDEF : LDPK_DEF;
332 if (strncmp(info.vis, "INTERNAL", 8) == 0)
334 else if (strncmp(info.vis, "HIDDEN", 6) == 0)
336 else if (strncmp(info.vis, "PROTECTED", 9) == 0)
337 vis = LDPV_PROTECTED;
341 /* If the symbol is listed in the options list, special-case
342 it as a comdat symbol. */
344 for (i = 0; i < nopts; ++i)
346 if (info.name != NULL && strcmp(info.name, opts[i]) == 0)
353 if (nsyms >= maxsyms)
355 syms = (struct ld_plugin_symbol*)
356 realloc(syms, sizeof(struct ld_plugin_symbol) * maxsyms * 2);
362 if (info.name == NULL)
363 syms[nsyms].name = NULL;
366 len = strlen(info.name);
367 syms[nsyms].name = malloc(len + 1);
368 strncpy(syms[nsyms].name, info.name, len + 1);
370 syms[nsyms].version = NULL;
371 syms[nsyms].def = def;
372 syms[nsyms].visibility = vis;
373 syms[nsyms].size = info.size;
374 syms[nsyms].comdat_key = is_comdat ? syms[nsyms].name : NULL;
375 syms[nsyms].resolution = LDPR_UNKNOWN;
379 claimed_file = (struct claimed_file*) malloc(sizeof(struct claimed_file));
380 if (claimed_file == NULL)
383 claimed_file->name = file->name;
384 claimed_file->handle = file->handle;
385 claimed_file->nsyms = nsyms;
386 claimed_file->syms = syms;
387 claimed_file->next = NULL;
388 if (last_claimed_file == NULL)
389 first_claimed_file = claimed_file;
391 last_claimed_file->next = claimed_file;
392 last_claimed_file = claimed_file;
394 (*message)(LDPL_INFO, "%s: claiming file, adding %d symbols",
398 (*add_symbols)(file->handle, nsyms, syms);
401 if (irfile_was_opened)
406 enum ld_plugin_status
407 all_symbols_read_hook(void)
411 struct claimed_file* claimed_file;
412 struct ld_plugin_input_file file;
415 struct sym_info info;
419 const char* filename;
421 (*message)(LDPL_INFO, "all symbols read hook called");
423 if (get_symbols_v2 == NULL)
425 fprintf(stderr, "tv_get_symbols (v2) interface missing\n");
429 for (claimed_file = first_claimed_file;
430 claimed_file != NULL;
431 claimed_file = claimed_file->next)
433 (*get_symbols_v2)(claimed_file->handle, claimed_file->nsyms,
436 for (i = 0; i < claimed_file->nsyms; ++i)
438 switch (claimed_file->syms[i].resolution)
446 case LDPR_PREVAILING_DEF:
447 res = "PREVAILING_DEF_REG";
449 case LDPR_PREVAILING_DEF_IRONLY:
450 res = "PREVAILING_DEF_IRONLY";
452 case LDPR_PREVAILING_DEF_IRONLY_EXP:
453 res = "PREVAILING_DEF_IRONLY_EXP";
455 case LDPR_PREEMPTED_REG:
456 res = "PREEMPTED_REG";
458 case LDPR_PREEMPTED_IR:
459 res = "PREEMPTED_IR";
461 case LDPR_RESOLVED_IR:
464 case LDPR_RESOLVED_EXEC:
465 res = "RESOLVED_EXEC";
467 case LDPR_RESOLVED_DYN:
468 res = "RESOLVED_DYN";
474 (*message)(LDPL_INFO, "%s: %s: %s", claimed_file->name,
475 claimed_file->syms[i].name, res);
479 if (add_input_file == NULL)
481 fprintf(stderr, "tv_add_input_file interface missing\n");
484 if (get_input_file == NULL)
486 fprintf(stderr, "tv_get_input_file interface missing\n");
489 if (release_input_file == NULL)
491 fprintf(stderr, "tv_release_input_file interface missing\n");
495 for (claimed_file = first_claimed_file;
496 claimed_file != NULL;
497 claimed_file = claimed_file->next)
499 int irfile_was_opened = 0;
502 (*get_input_file) (claimed_file->handle, &file);
504 if (file.offset == 0)
505 snprintf(syms_name, sizeof(syms_name), "%s.syms", file.name);
507 snprintf(syms_name, sizeof(syms_name), "%s-%d.syms",
508 file.name, (int)file.offset);
509 irfile = fopen(syms_name, "r");
512 irfile_was_opened = 1;
513 end_offset = 1 << 20;
516 if (!irfile_was_opened)
518 irfile = fdopen(file.fd, "r");
519 (void)fseek(irfile, file.offset, SEEK_SET);
520 end_offset = file.offset + file.filesize;
523 /* Look for the beginning of output from readelf -s. */
524 len = fread(buf, 1, 13, irfile);
525 if (len < 13 || strncmp(buf, "\nSymbol table", 13) != 0)
527 fprintf(stderr, "%s: can't re-read original input file\n",
532 /* Skip the two header lines. */
533 (void) fgets(buf, sizeof(buf), irfile);
534 (void) fgets(buf, sizeof(buf), irfile);
537 while (ftell(irfile) < end_offset
538 && fgets(buf, sizeof(buf), irfile) != NULL)
540 parse_readelf_line(buf, &info);
542 /* Look for file name. */
543 if (strncmp(info.type, "FILE", 4) == 0)
545 len = strlen(info.name);
547 strncpy(p, info.name, len + 1);
553 if (irfile_was_opened)
556 (*release_input_file) (claimed_file->handle);
558 if (filename == NULL)
559 filename = claimed_file->name;
561 if (claimed_file->nsyms == 0)
564 if (strlen(filename) >= sizeof(buf))
566 (*message)(LDPL_FATAL, "%s: filename too long", filename);
569 strcpy(buf, filename);
570 p = strrchr(buf, '.');
572 || (strcmp(p, ".syms") != 0
573 && strcmp(p, ".c") != 0
574 && strcmp(p, ".cc") != 0))
576 (*message)(LDPL_FATAL, "%s: filename has unknown suffix",
582 (*message)(LDPL_INFO, "%s: adding new input file", buf);
583 (*add_input_file)(buf);
589 enum ld_plugin_status
592 (*message)(LDPL_INFO, "cleanup hook called");
597 parse_readelf_line(char* p, struct sym_info* info)
604 p += strcspn(p, " ");
608 p += strcspn(p, " ");
612 info->size = atoi(p);
613 p += strcspn(p, " ");
618 p += strcspn(p, " ");
623 p += strcspn(p, " ");
626 /* Visibility field. */
628 p += strcspn(p, " ");
634 p += strcspn(p, "]");
635 p += strspn(p, "] ");
640 p += strcspn(p, " ");
644 /* FIXME: Look for version. */
648 else if (p[len-1] == '\n')