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