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