Revert bfd part of "Silence gcc-8 warnings"
[deliverable/binutils-gdb.git] / gold / testsuite / plugin_test.c
1 /* test_plugin.c -- simple linker plugin test
2
3 Copyright (C) 2008-2018 Free Software Foundation, Inc.
4 Written by Cary Coutant <ccoutant@google.com>.
5
6 This file is part of gold.
7
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.
12
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.
17
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. */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include "plugin-api.h"
31
32 struct claimed_file
33 {
34 const char* name;
35 void* handle;
36 int nsyms;
37 struct ld_plugin_symbol* syms;
38 struct claimed_file* next;
39 };
40
41 struct sym_info
42 {
43 int size;
44 char* type;
45 char* bind;
46 char* vis;
47 char* sect;
48 char* name;
49 };
50
51 static struct claimed_file* first_claimed_file = NULL;
52 static struct claimed_file* last_claimed_file = NULL;
53
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_get_symbols get_symbols_v3 = NULL;
61 static ld_plugin_add_input_file add_input_file = NULL;
62 static ld_plugin_message message = NULL;
63 static ld_plugin_get_input_file get_input_file = NULL;
64 static ld_plugin_release_input_file release_input_file = NULL;
65 static ld_plugin_get_input_section_count get_input_section_count = NULL;
66 static ld_plugin_get_input_section_type get_input_section_type = NULL;
67 static ld_plugin_get_input_section_name get_input_section_name = NULL;
68 static ld_plugin_get_input_section_contents get_input_section_contents = NULL;
69 static ld_plugin_update_section_order update_section_order = NULL;
70 static ld_plugin_allow_section_ordering allow_section_ordering = NULL;
71 static ld_plugin_get_wrap_symbols get_wrap_symbols = NULL;
72
73 #define MAXOPTS 10
74
75 static const char *opts[MAXOPTS];
76 static int nopts = 0;
77
78 enum ld_plugin_status onload(struct ld_plugin_tv *tv);
79 enum ld_plugin_status claim_file_hook(const struct ld_plugin_input_file *file,
80 int *claimed);
81 enum ld_plugin_status all_symbols_read_hook(void);
82 enum ld_plugin_status cleanup_hook(void);
83
84 static void parse_readelf_line(char*, struct sym_info*);
85
86 enum ld_plugin_status
87 onload(struct ld_plugin_tv *tv)
88 {
89 struct ld_plugin_tv *entry;
90 int api_version = 0;
91 int gold_version = 0;
92 int i;
93
94 for (entry = tv; entry->tv_tag != LDPT_NULL; ++entry)
95 {
96 switch (entry->tv_tag)
97 {
98 case LDPT_API_VERSION:
99 api_version = entry->tv_u.tv_val;
100 break;
101 case LDPT_GOLD_VERSION:
102 gold_version = entry->tv_u.tv_val;
103 break;
104 case LDPT_LINKER_OUTPUT:
105 break;
106 case LDPT_OPTION:
107 if (nopts < MAXOPTS)
108 opts[nopts++] = entry->tv_u.tv_string;
109 break;
110 case LDPT_REGISTER_CLAIM_FILE_HOOK:
111 register_claim_file_hook = entry->tv_u.tv_register_claim_file;
112 break;
113 case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK:
114 register_all_symbols_read_hook =
115 entry->tv_u.tv_register_all_symbols_read;
116 break;
117 case LDPT_REGISTER_CLEANUP_HOOK:
118 register_cleanup_hook = entry->tv_u.tv_register_cleanup;
119 break;
120 case LDPT_ADD_SYMBOLS:
121 add_symbols = entry->tv_u.tv_add_symbols;
122 break;
123 case LDPT_GET_SYMBOLS:
124 get_symbols = entry->tv_u.tv_get_symbols;
125 break;
126 case LDPT_GET_SYMBOLS_V2:
127 get_symbols_v2 = entry->tv_u.tv_get_symbols;
128 break;
129 case LDPT_GET_SYMBOLS_V3:
130 get_symbols_v3 = entry->tv_u.tv_get_symbols;
131 break;
132 case LDPT_ADD_INPUT_FILE:
133 add_input_file = entry->tv_u.tv_add_input_file;
134 break;
135 case LDPT_MESSAGE:
136 message = entry->tv_u.tv_message;
137 break;
138 case LDPT_GET_INPUT_FILE:
139 get_input_file = entry->tv_u.tv_get_input_file;
140 break;
141 case LDPT_RELEASE_INPUT_FILE:
142 release_input_file = entry->tv_u.tv_release_input_file;
143 break;
144 case LDPT_GET_INPUT_SECTION_COUNT:
145 get_input_section_count = *entry->tv_u.tv_get_input_section_count;
146 break;
147 case LDPT_GET_INPUT_SECTION_TYPE:
148 get_input_section_type = *entry->tv_u.tv_get_input_section_type;
149 break;
150 case LDPT_GET_INPUT_SECTION_NAME:
151 get_input_section_name = *entry->tv_u.tv_get_input_section_name;
152 break;
153 case LDPT_GET_INPUT_SECTION_CONTENTS:
154 get_input_section_contents = *entry->tv_u.tv_get_input_section_contents;
155 break;
156 case LDPT_UPDATE_SECTION_ORDER:
157 update_section_order = *entry->tv_u.tv_update_section_order;
158 break;
159 case LDPT_ALLOW_SECTION_ORDERING:
160 allow_section_ordering = *entry->tv_u.tv_allow_section_ordering;
161 break;
162 case LDPT_GET_WRAP_SYMBOLS:
163 get_wrap_symbols = *entry->tv_u.tv_get_wrap_symbols;
164 break;
165 default:
166 break;
167 }
168 }
169
170 if (message == NULL)
171 {
172 fprintf(stderr, "tv_message interface missing\n");
173 return LDPS_ERR;
174 }
175
176 if (register_claim_file_hook == NULL)
177 {
178 fprintf(stderr, "tv_register_claim_file_hook interface missing\n");
179 return LDPS_ERR;
180 }
181
182 if (register_all_symbols_read_hook == NULL)
183 {
184 fprintf(stderr, "tv_register_all_symbols_read_hook interface missing\n");
185 return LDPS_ERR;
186 }
187
188 if (register_cleanup_hook == NULL)
189 {
190 fprintf(stderr, "tv_register_cleanup_hook interface missing\n");
191 return LDPS_ERR;
192 }
193
194 (*message)(LDPL_INFO, "API version: %d", api_version);
195 (*message)(LDPL_INFO, "gold version: %d", gold_version);
196
197 for (i = 0; i < nopts; ++i)
198 (*message)(LDPL_INFO, "option: %s", opts[i]);
199
200 if ((*register_claim_file_hook)(claim_file_hook) != LDPS_OK)
201 {
202 (*message)(LDPL_ERROR, "error registering claim file hook");
203 return LDPS_ERR;
204 }
205
206 if ((*register_all_symbols_read_hook)(all_symbols_read_hook) != LDPS_OK)
207 {
208 (*message)(LDPL_ERROR, "error registering all symbols read hook");
209 return LDPS_ERR;
210 }
211
212 if ((*register_cleanup_hook)(cleanup_hook) != LDPS_OK)
213 {
214 (*message)(LDPL_ERROR, "error registering cleanup hook");
215 return LDPS_ERR;
216 }
217
218 if (get_input_section_count == NULL)
219 {
220 fprintf(stderr, "tv_get_input_section_count interface missing\n");
221 return LDPS_ERR;
222 }
223
224 if (get_input_section_type == NULL)
225 {
226 fprintf(stderr, "tv_get_input_section_type interface missing\n");
227 return LDPS_ERR;
228 }
229
230 if (get_input_section_name == NULL)
231 {
232 fprintf(stderr, "tv_get_input_section_name interface missing\n");
233 return LDPS_ERR;
234 }
235
236 if (get_input_section_contents == NULL)
237 {
238 fprintf(stderr, "tv_get_input_section_contents interface missing\n");
239 return LDPS_ERR;
240 }
241
242 if (update_section_order == NULL)
243 {
244 fprintf(stderr, "tv_update_section_order interface missing\n");
245 return LDPS_ERR;
246 }
247
248 if (allow_section_ordering == NULL)
249 {
250 fprintf(stderr, "tv_allow_section_ordering interface missing\n");
251 return LDPS_ERR;
252 }
253
254 if (get_wrap_symbols == NULL)
255 {
256 fprintf(stderr, "tv_get_wrap_symbols interface missing\n");
257 return LDPS_ERR;
258 }
259 else
260 {
261 const char **wrap_symbols;
262 uint64_t count = 0;
263 if (get_wrap_symbols(&count, &wrap_symbols) == LDPS_OK)
264 {
265 (*message)(LDPL_INFO, "Number of wrap symbols = %lu", count);
266 for (; count > 0; --count)
267 (*message)(LDPL_INFO, "Wrap symbol %s", wrap_symbols[count - 1]);
268 }
269 else
270 {
271 fprintf(stderr, "tv_get_wrap_symbols interface call failed\n");
272 return LDPS_ERR;
273 }
274 }
275
276 return LDPS_OK;
277 }
278
279 enum ld_plugin_status
280 claim_file_hook (const struct ld_plugin_input_file* file, int* claimed)
281 {
282 int len;
283 off_t end_offset;
284 char buf[160];
285 struct claimed_file* claimed_file;
286 struct ld_plugin_symbol* syms;
287 int nsyms = 0;
288 int maxsyms = 0;
289 FILE* irfile;
290 struct sym_info info;
291 int weak;
292 int def;
293 int vis;
294 int is_comdat;
295 int i;
296 int irfile_was_opened = 0;
297 char syms_name[80];
298
299 (*message)(LDPL_INFO,
300 "%s: claim file hook called (offset = %ld, size = %ld)",
301 file->name, (long)file->offset, (long)file->filesize);
302
303 /* Look for matching syms file for an archive member. */
304 if (file->offset == 0)
305 snprintf(syms_name, sizeof(syms_name), "%s.syms", file->name);
306 else
307 snprintf(syms_name, sizeof(syms_name), "%s-%d.syms",
308 file->name, (int)file->offset);
309 irfile = fopen(syms_name, "r");
310 if (irfile != NULL)
311 {
312 irfile_was_opened = 1;
313 end_offset = 1 << 20;
314 }
315
316 /* Otherwise, see if the file itself is a syms file. */
317 if (!irfile_was_opened)
318 {
319 irfile = fdopen(file->fd, "r");
320 (void)fseek(irfile, file->offset, SEEK_SET);
321 end_offset = file->offset + file->filesize;
322 }
323
324 /* Look for the beginning of output from readelf -s. */
325 len = fread(buf, 1, 13, irfile);
326 if (len < 13 || strncmp(buf, "\nSymbol table", 13) != 0)
327 return LDPS_OK;
328
329 /* Skip the two header lines. */
330 (void) fgets(buf, sizeof(buf), irfile);
331 (void) fgets(buf, sizeof(buf), irfile);
332
333 if (add_symbols == NULL)
334 {
335 fprintf(stderr, "tv_add_symbols interface missing\n");
336 return LDPS_ERR;
337 }
338
339 /* Parse the output from readelf. The columns are:
340 Index Value Size Type Binding Visibility Section Name. */
341 syms = (struct ld_plugin_symbol*)malloc(sizeof(struct ld_plugin_symbol) * 8);
342 if (syms == NULL)
343 return LDPS_ERR;
344 maxsyms = 8;
345 while (ftell(irfile) < end_offset
346 && fgets(buf, sizeof(buf), irfile) != NULL)
347 {
348 parse_readelf_line(buf, &info);
349
350 /* Ignore local symbols. */
351 if (strncmp(info.bind, "LOCAL", 5) == 0)
352 continue;
353
354 weak = strncmp(info.bind, "WEAK", 4) == 0;
355 if (strncmp(info.sect, "UND", 3) == 0)
356 def = weak ? LDPK_WEAKUNDEF : LDPK_UNDEF;
357 else if (strncmp(info.sect, "COM", 3) == 0)
358 def = LDPK_COMMON;
359 else
360 def = weak ? LDPK_WEAKDEF : LDPK_DEF;
361
362 if (strncmp(info.vis, "INTERNAL", 8) == 0)
363 vis = LDPV_INTERNAL;
364 else if (strncmp(info.vis, "HIDDEN", 6) == 0)
365 vis = LDPV_HIDDEN;
366 else if (strncmp(info.vis, "PROTECTED", 9) == 0)
367 vis = LDPV_PROTECTED;
368 else
369 vis = LDPV_DEFAULT;
370
371 /* If the symbol is listed in the options list, special-case
372 it as a comdat symbol. */
373 is_comdat = 0;
374 for (i = 0; i < nopts; ++i)
375 {
376 if (info.name != NULL && strcmp(info.name, opts[i]) == 0)
377 {
378 is_comdat = 1;
379 break;
380 }
381 }
382
383 if (nsyms >= maxsyms)
384 {
385 syms = (struct ld_plugin_symbol*)
386 realloc(syms, sizeof(struct ld_plugin_symbol) * maxsyms * 2);
387 if (syms == NULL)
388 return LDPS_ERR;
389 maxsyms *= 2;
390 }
391
392 if (info.name == NULL)
393 syms[nsyms].name = NULL;
394 else
395 {
396 len = strlen(info.name);
397 syms[nsyms].name = malloc(len + 1);
398 strncpy(syms[nsyms].name, info.name, len + 1);
399 }
400 syms[nsyms].version = NULL;
401 syms[nsyms].def = def;
402 syms[nsyms].visibility = vis;
403 syms[nsyms].size = info.size;
404 syms[nsyms].comdat_key = is_comdat ? syms[nsyms].name : NULL;
405 syms[nsyms].resolution = LDPR_UNKNOWN;
406 ++nsyms;
407 }
408
409 claimed_file = (struct claimed_file*) malloc(sizeof(struct claimed_file));
410 if (claimed_file == NULL)
411 return LDPS_ERR;
412
413 claimed_file->name = file->name;
414 claimed_file->handle = file->handle;
415 claimed_file->nsyms = nsyms;
416 claimed_file->syms = syms;
417 claimed_file->next = NULL;
418 if (last_claimed_file == NULL)
419 first_claimed_file = claimed_file;
420 else
421 last_claimed_file->next = claimed_file;
422 last_claimed_file = claimed_file;
423
424 (*message)(LDPL_INFO, "%s: claiming file, adding %d symbols",
425 file->name, nsyms);
426
427 if (nsyms > 0)
428 (*add_symbols)(file->handle, nsyms, syms);
429
430 *claimed = 1;
431 if (irfile_was_opened)
432 fclose(irfile);
433 return LDPS_OK;
434 }
435
436 enum ld_plugin_status
437 all_symbols_read_hook(void)
438 {
439 int i;
440 const char* res;
441 struct claimed_file* claimed_file;
442 struct ld_plugin_input_file file;
443 FILE* irfile;
444 off_t end_offset;
445 struct sym_info info;
446 int len;
447 char buf[160];
448 char* p;
449 const char* filename;
450
451 (*message)(LDPL_INFO, "all symbols read hook called");
452
453 if (get_symbols_v3 == NULL)
454 {
455 fprintf(stderr, "tv_get_symbols (v3) interface missing\n");
456 return LDPS_ERR;
457 }
458
459 for (claimed_file = first_claimed_file;
460 claimed_file != NULL;
461 claimed_file = claimed_file->next)
462 {
463 enum ld_plugin_status status = (*get_symbols_v3)(
464 claimed_file->handle, claimed_file->nsyms, claimed_file->syms);
465 if (status == LDPS_NO_SYMS)
466 {
467 (*message)(LDPL_INFO, "%s: no symbols", claimed_file->name);
468 continue;
469 }
470
471 for (i = 0; i < claimed_file->nsyms; ++i)
472 {
473 switch (claimed_file->syms[i].resolution)
474 {
475 case LDPR_UNKNOWN:
476 res = "UNKNOWN";
477 break;
478 case LDPR_UNDEF:
479 res = "UNDEF";
480 break;
481 case LDPR_PREVAILING_DEF:
482 res = "PREVAILING_DEF_REG";
483 break;
484 case LDPR_PREVAILING_DEF_IRONLY:
485 res = "PREVAILING_DEF_IRONLY";
486 break;
487 case LDPR_PREVAILING_DEF_IRONLY_EXP:
488 res = "PREVAILING_DEF_IRONLY_EXP";
489 break;
490 case LDPR_PREEMPTED_REG:
491 res = "PREEMPTED_REG";
492 break;
493 case LDPR_PREEMPTED_IR:
494 res = "PREEMPTED_IR";
495 break;
496 case LDPR_RESOLVED_IR:
497 res = "RESOLVED_IR";
498 break;
499 case LDPR_RESOLVED_EXEC:
500 res = "RESOLVED_EXEC";
501 break;
502 case LDPR_RESOLVED_DYN:
503 res = "RESOLVED_DYN";
504 break;
505 default:
506 res = "?";
507 break;
508 }
509 (*message)(LDPL_INFO, "%s: %s: %s", claimed_file->name,
510 claimed_file->syms[i].name, res);
511 }
512 }
513
514 if (add_input_file == NULL)
515 {
516 fprintf(stderr, "tv_add_input_file interface missing\n");
517 return LDPS_ERR;
518 }
519 if (get_input_file == NULL)
520 {
521 fprintf(stderr, "tv_get_input_file interface missing\n");
522 return LDPS_ERR;
523 }
524 if (release_input_file == NULL)
525 {
526 fprintf(stderr, "tv_release_input_file interface missing\n");
527 return LDPS_ERR;
528 }
529
530 for (claimed_file = first_claimed_file;
531 claimed_file != NULL;
532 claimed_file = claimed_file->next)
533 {
534 int irfile_was_opened = 0;
535 char syms_name[80];
536
537 (*get_input_file) (claimed_file->handle, &file);
538
539 if (file.offset == 0)
540 snprintf(syms_name, sizeof(syms_name), "%s.syms", file.name);
541 else
542 snprintf(syms_name, sizeof(syms_name), "%s-%d.syms",
543 file.name, (int)file.offset);
544 irfile = fopen(syms_name, "r");
545 if (irfile != NULL)
546 {
547 irfile_was_opened = 1;
548 end_offset = 1 << 20;
549 }
550
551 if (!irfile_was_opened)
552 {
553 irfile = fdopen(file.fd, "r");
554 (void)fseek(irfile, file.offset, SEEK_SET);
555 end_offset = file.offset + file.filesize;
556 }
557
558 /* Look for the beginning of output from readelf -s. */
559 len = fread(buf, 1, 13, irfile);
560 if (len < 13 || strncmp(buf, "\nSymbol table", 13) != 0)
561 {
562 fprintf(stderr, "%s: can't re-read original input file\n",
563 claimed_file->name);
564 return LDPS_ERR;
565 }
566
567 /* Skip the two header lines. */
568 (void) fgets(buf, sizeof(buf), irfile);
569 (void) fgets(buf, sizeof(buf), irfile);
570
571 filename = NULL;
572 while (ftell(irfile) < end_offset
573 && fgets(buf, sizeof(buf), irfile) != NULL)
574 {
575 parse_readelf_line(buf, &info);
576
577 /* Look for file name. */
578 if (strncmp(info.type, "FILE", 4) == 0)
579 {
580 len = strlen(info.name);
581 p = malloc(len + 1);
582 strncpy(p, info.name, len + 1);
583 filename = p;
584 break;
585 }
586 }
587
588 if (irfile_was_opened)
589 fclose(irfile);
590
591 (*release_input_file) (claimed_file->handle);
592
593 if (filename == NULL)
594 filename = claimed_file->name;
595
596 if (claimed_file->nsyms == 0)
597 continue;
598
599 if (strlen(filename) >= sizeof(buf))
600 {
601 (*message)(LDPL_FATAL, "%s: filename too long", filename);
602 return LDPS_ERR;
603 }
604 strcpy(buf, filename);
605 p = strrchr(buf, '.');
606 if (p == NULL
607 || (strcmp(p, ".syms") != 0
608 && strcmp(p, ".c") != 0
609 && strcmp(p, ".cc") != 0))
610 {
611 (*message)(LDPL_FATAL, "%s: filename has unknown suffix",
612 filename);
613 return LDPS_ERR;
614 }
615 p[1] = 'o';
616 p[2] = '\0';
617 (*message)(LDPL_INFO, "%s: adding new input file", buf);
618 (*add_input_file)(buf);
619 }
620
621 return LDPS_OK;
622 }
623
624 enum ld_plugin_status
625 cleanup_hook(void)
626 {
627 (*message)(LDPL_INFO, "cleanup hook called");
628 return LDPS_OK;
629 }
630
631 static void
632 parse_readelf_line(char* p, struct sym_info* info)
633 {
634 int len;
635
636 p += strspn(p, " ");
637
638 /* Index field. */
639 p += strcspn(p, " ");
640 p += strspn(p, " ");
641
642 /* Value field. */
643 p += strcspn(p, " ");
644 p += strspn(p, " ");
645
646 /* Size field. */
647 info->size = atoi(p);
648 p += strcspn(p, " ");
649 p += strspn(p, " ");
650
651 /* Type field. */
652 info->type = p;
653 p += strcspn(p, " ");
654 p += strspn(p, " ");
655
656 /* Binding field. */
657 info->bind = p;
658 p += strcspn(p, " ");
659 p += strspn(p, " ");
660
661 /* Visibility field. */
662 info->vis = p;
663 p += strcspn(p, " ");
664 p += strspn(p, " ");
665
666 if (*p == '[')
667 {
668 /* Skip st_other. */
669 p += strcspn(p, "]");
670 p += strspn(p, "] ");
671 }
672
673 /* Section field. */
674 info->sect = p;
675 p += strcspn(p, " ");
676 p += strspn(p, " ");
677
678 /* Name field. */
679 /* FIXME: Look for version. */
680 len = strlen(p);
681 if (len == 0)
682 p = NULL;
683 else if (p[len-1] == '\n')
684 p[--len] = '\0';
685 info->name = p;
686 }
This page took 0.065528 seconds and 4 git commands to generate.