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