1 /* test_plugin.c -- simple linker plugin test
3 Copyright 2008, 2009 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. */
26 #include "plugin-api.h"
33 struct ld_plugin_symbol
* syms
;
34 struct claimed_file
* next
;
47 static struct claimed_file
* first_claimed_file
= NULL
;
48 static struct claimed_file
* last_claimed_file
= NULL
;
50 static ld_plugin_register_claim_file register_claim_file_hook
= NULL
;
51 static ld_plugin_register_all_symbols_read register_all_symbols_read_hook
= NULL
;
52 static ld_plugin_register_cleanup register_cleanup_hook
= NULL
;
53 static ld_plugin_add_symbols add_symbols
= NULL
;
54 static ld_plugin_get_symbols get_symbols
= NULL
;
55 static ld_plugin_add_input_file add_input_file
= NULL
;
56 static ld_plugin_message message
= NULL
;
57 static ld_plugin_get_input_file get_input_file
= NULL
;
58 static ld_plugin_release_input_file release_input_file
= NULL
;
62 static const char *opts
[MAXOPTS
];
65 enum ld_plugin_status
onload(struct ld_plugin_tv
*tv
);
66 enum ld_plugin_status
claim_file_hook(const struct ld_plugin_input_file
*file
,
68 enum ld_plugin_status
all_symbols_read_hook(void);
69 enum ld_plugin_status
cleanup_hook(void);
71 static void parse_readelf_line(char*, struct sym_info
*);
74 onload(struct ld_plugin_tv
*tv
)
76 struct ld_plugin_tv
*entry
;
81 for (entry
= tv
; entry
->tv_tag
!= LDPT_NULL
; ++entry
)
83 switch (entry
->tv_tag
)
85 case LDPT_API_VERSION
:
86 api_version
= entry
->tv_u
.tv_val
;
88 case LDPT_GOLD_VERSION
:
89 gold_version
= entry
->tv_u
.tv_val
;
91 case LDPT_LINKER_OUTPUT
:
95 opts
[nopts
++] = entry
->tv_u
.tv_string
;
97 case LDPT_REGISTER_CLAIM_FILE_HOOK
:
98 register_claim_file_hook
= entry
->tv_u
.tv_register_claim_file
;
100 case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK
:
101 register_all_symbols_read_hook
=
102 entry
->tv_u
.tv_register_all_symbols_read
;
104 case LDPT_REGISTER_CLEANUP_HOOK
:
105 register_cleanup_hook
= entry
->tv_u
.tv_register_cleanup
;
107 case LDPT_ADD_SYMBOLS
:
108 add_symbols
= entry
->tv_u
.tv_add_symbols
;
110 case LDPT_GET_SYMBOLS
:
111 get_symbols
= entry
->tv_u
.tv_get_symbols
;
113 case LDPT_ADD_INPUT_FILE
:
114 add_input_file
= entry
->tv_u
.tv_add_input_file
;
117 message
= entry
->tv_u
.tv_message
;
119 case LDPT_GET_INPUT_FILE
:
120 get_input_file
= entry
->tv_u
.tv_get_input_file
;
122 case LDPT_RELEASE_INPUT_FILE
:
123 release_input_file
= entry
->tv_u
.tv_release_input_file
;
132 fprintf(stderr
, "tv_message interface missing\n");
136 if (register_claim_file_hook
== NULL
)
138 fprintf(stderr
, "tv_register_claim_file_hook interface missing\n");
142 if (register_all_symbols_read_hook
== NULL
)
144 fprintf(stderr
, "tv_register_all_symbols_read_hook interface missing\n");
148 if (register_cleanup_hook
== NULL
)
150 fprintf(stderr
, "tv_register_cleanup_hook interface missing\n");
154 (*message
)(LDPL_INFO
, "API version: %d", api_version
);
155 (*message
)(LDPL_INFO
, "gold version: %d", gold_version
);
157 for (i
= 0; i
< nopts
; ++i
)
158 (*message
)(LDPL_INFO
, "option: %s", opts
[i
]);
160 if ((*register_claim_file_hook
)(claim_file_hook
) != LDPS_OK
)
162 (*message
)(LDPL_ERROR
, "error registering claim file hook");
166 if ((*register_all_symbols_read_hook
)(all_symbols_read_hook
) != LDPS_OK
)
168 (*message
)(LDPL_ERROR
, "error registering all symbols read hook");
172 if ((*register_cleanup_hook
)(cleanup_hook
) != LDPS_OK
)
174 (*message
)(LDPL_ERROR
, "error registering cleanup hook");
181 enum ld_plugin_status
182 claim_file_hook (const struct ld_plugin_input_file
* file
, int* claimed
)
187 struct claimed_file
* claimed_file
;
188 struct ld_plugin_symbol
* syms
;
192 struct sym_info info
;
199 (*message
)(LDPL_INFO
,
200 "%s: claim file hook called (offset = %ld, size = %ld)",
201 file
->name
, (long)file
->offset
, (long)file
->filesize
);
203 /* Look for the beginning of output from readelf -s. */
204 irfile
= fdopen(file
->fd
, "r");
205 (void)fseek(irfile
, file
->offset
, SEEK_SET
);
206 end_offset
= file
->offset
+ file
->filesize
;
207 len
= fread(buf
, 1, 13, irfile
);
208 if (len
< 13 || strncmp(buf
, "\nSymbol table", 13) != 0)
211 /* Skip the two header lines. */
212 (void) fgets(buf
, sizeof(buf
), irfile
);
213 (void) fgets(buf
, sizeof(buf
), irfile
);
215 if (add_symbols
== NULL
)
217 fprintf(stderr
, "tv_add_symbols interface missing\n");
221 /* Parse the output from readelf. The columns are:
222 Index Value Size Type Binding Visibility Section Name. */
223 syms
= (struct ld_plugin_symbol
*)malloc(sizeof(struct ld_plugin_symbol
) * 8);
227 while (ftell(irfile
) < end_offset
228 && fgets(buf
, sizeof(buf
), irfile
) != NULL
)
230 parse_readelf_line(buf
, &info
);
232 /* Ignore local symbols. */
233 if (strncmp(info
.bind
, "LOCAL", 5) == 0)
236 weak
= strncmp(info
.bind
, "WEAK", 4) == 0;
237 if (strncmp(info
.sect
, "UND", 3) == 0)
238 def
= weak
? LDPK_WEAKUNDEF
: LDPK_UNDEF
;
239 else if (strncmp(info
.sect
, "COM", 3) == 0)
242 def
= weak
? LDPK_WEAKDEF
: LDPK_DEF
;
244 if (strncmp(info
.vis
, "INTERNAL", 8) == 0)
246 else if (strncmp(info
.vis
, "HIDDEN", 6) == 0)
248 else if (strncmp(info
.vis
, "PROTECTED", 9) == 0)
249 vis
= LDPV_PROTECTED
;
253 /* If the symbol is listed in the options list, special-case
254 it as a comdat symbol. */
256 for (i
= 0; i
< nopts
; ++i
)
258 if (info
.name
!= NULL
&& strcmp(info
.name
, opts
[i
]) == 0)
265 if (nsyms
>= maxsyms
)
267 syms
= (struct ld_plugin_symbol
*)
268 realloc(syms
, sizeof(struct ld_plugin_symbol
) * maxsyms
* 2);
274 if (info
.name
== NULL
)
275 syms
[nsyms
].name
= NULL
;
278 len
= strlen(info
.name
);
279 syms
[nsyms
].name
= malloc(len
+ 1);
280 strncpy(syms
[nsyms
].name
, info
.name
, len
+ 1);
282 syms
[nsyms
].version
= NULL
;
283 syms
[nsyms
].def
= def
;
284 syms
[nsyms
].visibility
= vis
;
285 syms
[nsyms
].size
= info
.size
;
286 syms
[nsyms
].comdat_key
= is_comdat
? syms
[nsyms
].name
: NULL
;
287 syms
[nsyms
].resolution
= LDPR_UNKNOWN
;
291 claimed_file
= (struct claimed_file
*) malloc(sizeof(struct claimed_file
));
292 if (claimed_file
== NULL
)
295 claimed_file
->name
= file
->name
;
296 claimed_file
->handle
= file
->handle
;
297 claimed_file
->nsyms
= nsyms
;
298 claimed_file
->syms
= syms
;
299 claimed_file
->next
= NULL
;
300 if (last_claimed_file
== NULL
)
301 first_claimed_file
= claimed_file
;
303 last_claimed_file
->next
= claimed_file
;
304 last_claimed_file
= claimed_file
;
306 (*message
)(LDPL_INFO
, "%s: claiming file, adding %d symbols",
310 (*add_symbols
)(file
->handle
, nsyms
, syms
);
316 enum ld_plugin_status
317 all_symbols_read_hook(void)
321 struct claimed_file
* claimed_file
;
322 struct ld_plugin_input_file file
;
325 struct sym_info info
;
329 const char* filename
;
331 (*message
)(LDPL_INFO
, "all symbols read hook called");
333 if (get_symbols
== NULL
)
335 fprintf(stderr
, "tv_get_symbols interface missing\n");
339 for (claimed_file
= first_claimed_file
;
340 claimed_file
!= NULL
;
341 claimed_file
= claimed_file
->next
)
343 (*get_symbols
)(claimed_file
->handle
, claimed_file
->nsyms
,
346 for (i
= 0; i
< claimed_file
->nsyms
; ++i
)
348 switch (claimed_file
->syms
[i
].resolution
)
356 case LDPR_PREVAILING_DEF
:
357 res
= "PREVAILING_DEF_REG";
359 case LDPR_PREVAILING_DEF_IRONLY
:
360 res
= "PREVAILING_DEF_IRONLY";
362 case LDPR_PREEMPTED_REG
:
363 res
= "PREEMPTED_REG";
365 case LDPR_PREEMPTED_IR
:
366 res
= "PREEMPTED_IR";
368 case LDPR_RESOLVED_IR
:
371 case LDPR_RESOLVED_EXEC
:
372 res
= "RESOLVED_EXEC";
374 case LDPR_RESOLVED_DYN
:
375 res
= "RESOLVED_DYN";
381 (*message
)(LDPL_INFO
, "%s: %s: %s", claimed_file
->name
,
382 claimed_file
->syms
[i
].name
, res
);
386 if (add_input_file
== NULL
)
388 fprintf(stderr
, "tv_add_input_file interface missing\n");
391 if (get_input_file
== NULL
)
393 fprintf(stderr
, "tv_get_input_file interface missing\n");
396 if (release_input_file
== NULL
)
398 fprintf(stderr
, "tv_release_input_file interface missing\n");
402 for (claimed_file
= first_claimed_file
;
403 claimed_file
!= NULL
;
404 claimed_file
= claimed_file
->next
)
406 (*get_input_file
) (claimed_file
->handle
, &file
);
408 /* Look for the beginning of output from readelf -s. */
409 irfile
= fdopen(file
.fd
, "r");
410 (void)fseek(irfile
, file
.offset
, SEEK_SET
);
411 end_offset
= file
.offset
+ file
.filesize
;
412 len
= fread(buf
, 1, 13, irfile
);
413 if (len
< 13 || strncmp(buf
, "\nSymbol table", 13) != 0)
415 fprintf(stderr
, "%s: can't re-read original input file\n",
420 /* Skip the two header lines. */
421 (void) fgets(buf
, sizeof(buf
), irfile
);
422 (void) fgets(buf
, sizeof(buf
), irfile
);
425 while (ftell(irfile
) < end_offset
426 && fgets(buf
, sizeof(buf
), irfile
) != NULL
)
428 parse_readelf_line(buf
, &info
);
430 /* Look for file name. */
431 if (strncmp(info
.type
, "FILE", 4) == 0)
433 len
= strlen(info
.name
);
435 strncpy(p
, info
.name
, len
+ 1);
441 (*release_input_file
) (claimed_file
->handle
);
443 if (filename
== NULL
)
444 filename
= claimed_file
->name
;
446 if (claimed_file
->nsyms
== 0)
449 if (strlen(filename
) >= sizeof(buf
))
451 (*message
)(LDPL_FATAL
, "%s: filename too long", filename
);
454 strcpy(buf
, filename
);
455 p
= strrchr(buf
, '.');
457 || (strcmp(p
, ".syms") != 0
458 && strcmp(p
, ".c") != 0
459 && strcmp(p
, ".cc") != 0))
461 (*message
)(LDPL_FATAL
, "%s: filename has unknown suffix",
467 (*message
)(LDPL_INFO
, "%s: adding new input file", buf
);
468 (*add_input_file
)(buf
);
474 enum ld_plugin_status
477 (*message
)(LDPL_INFO
, "cleanup hook called");
482 parse_readelf_line(char* p
, struct sym_info
* info
)
489 p
+= strcspn(p
, " ");
493 p
+= strcspn(p
, " ");
497 info
->size
= atoi(p
);
498 p
+= strcspn(p
, " ");
503 p
+= strcspn(p
, " ");
508 p
+= strcspn(p
, " ");
511 /* Visibility field. */
513 p
+= strcspn(p
, " ");
518 p
+= strcspn(p
, " ");
522 /* FIXME: Look for version. */
526 else if (p
[len
-1] == '\n')