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. */
30 #include "plugin-api.h"
37 struct ld_plugin_symbol
* syms
;
38 struct claimed_file
* next
;
51 static struct claimed_file
* first_claimed_file
= NULL
;
52 static struct claimed_file
* last_claimed_file
= NULL
;
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_add_input_file add_input_file
= NULL
;
60 static ld_plugin_message message
= NULL
;
61 static ld_plugin_get_input_file get_input_file
= NULL
;
62 static ld_plugin_release_input_file release_input_file
= NULL
;
66 static const char *opts
[MAXOPTS
];
69 enum ld_plugin_status
onload(struct ld_plugin_tv
*tv
);
70 enum ld_plugin_status
claim_file_hook(const struct ld_plugin_input_file
*file
,
72 enum ld_plugin_status
all_symbols_read_hook(void);
73 enum ld_plugin_status
cleanup_hook(void);
75 static void parse_readelf_line(char*, struct sym_info
*);
78 onload(struct ld_plugin_tv
*tv
)
80 struct ld_plugin_tv
*entry
;
85 for (entry
= tv
; entry
->tv_tag
!= LDPT_NULL
; ++entry
)
87 switch (entry
->tv_tag
)
89 case LDPT_API_VERSION
:
90 api_version
= entry
->tv_u
.tv_val
;
92 case LDPT_GOLD_VERSION
:
93 gold_version
= entry
->tv_u
.tv_val
;
95 case LDPT_LINKER_OUTPUT
:
99 opts
[nopts
++] = entry
->tv_u
.tv_string
;
101 case LDPT_REGISTER_CLAIM_FILE_HOOK
:
102 register_claim_file_hook
= entry
->tv_u
.tv_register_claim_file
;
104 case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK
:
105 register_all_symbols_read_hook
=
106 entry
->tv_u
.tv_register_all_symbols_read
;
108 case LDPT_REGISTER_CLEANUP_HOOK
:
109 register_cleanup_hook
= entry
->tv_u
.tv_register_cleanup
;
111 case LDPT_ADD_SYMBOLS
:
112 add_symbols
= entry
->tv_u
.tv_add_symbols
;
114 case LDPT_GET_SYMBOLS
:
115 get_symbols
= entry
->tv_u
.tv_get_symbols
;
117 case LDPT_ADD_INPUT_FILE
:
118 add_input_file
= entry
->tv_u
.tv_add_input_file
;
121 message
= entry
->tv_u
.tv_message
;
123 case LDPT_GET_INPUT_FILE
:
124 get_input_file
= entry
->tv_u
.tv_get_input_file
;
126 case LDPT_RELEASE_INPUT_FILE
:
127 release_input_file
= entry
->tv_u
.tv_release_input_file
;
136 fprintf(stderr
, "tv_message interface missing\n");
140 if (register_claim_file_hook
== NULL
)
142 fprintf(stderr
, "tv_register_claim_file_hook interface missing\n");
146 if (register_all_symbols_read_hook
== NULL
)
148 fprintf(stderr
, "tv_register_all_symbols_read_hook interface missing\n");
152 if (register_cleanup_hook
== NULL
)
154 fprintf(stderr
, "tv_register_cleanup_hook interface missing\n");
158 (*message
)(LDPL_INFO
, "API version: %d", api_version
);
159 (*message
)(LDPL_INFO
, "gold version: %d", gold_version
);
161 for (i
= 0; i
< nopts
; ++i
)
162 (*message
)(LDPL_INFO
, "option: %s", opts
[i
]);
164 if ((*register_claim_file_hook
)(claim_file_hook
) != LDPS_OK
)
166 (*message
)(LDPL_ERROR
, "error registering claim file hook");
170 if ((*register_all_symbols_read_hook
)(all_symbols_read_hook
) != LDPS_OK
)
172 (*message
)(LDPL_ERROR
, "error registering all symbols read hook");
176 if ((*register_cleanup_hook
)(cleanup_hook
) != LDPS_OK
)
178 (*message
)(LDPL_ERROR
, "error registering cleanup hook");
185 enum ld_plugin_status
186 claim_file_hook (const struct ld_plugin_input_file
* file
, int* claimed
)
191 struct claimed_file
* claimed_file
;
192 struct ld_plugin_symbol
* syms
;
196 struct sym_info info
;
203 (*message
)(LDPL_INFO
,
204 "%s: claim file hook called (offset = %ld, size = %ld)",
205 file
->name
, (long)file
->offset
, (long)file
->filesize
);
207 /* Look for the beginning of output from readelf -s. */
208 irfile
= fdopen(file
->fd
, "r");
209 (void)fseek(irfile
, file
->offset
, SEEK_SET
);
210 end_offset
= file
->offset
+ file
->filesize
;
211 len
= fread(buf
, 1, 13, irfile
);
212 if (len
< 13 || strncmp(buf
, "\nSymbol table", 13) != 0)
215 /* Skip the two header lines. */
216 (void) fgets(buf
, sizeof(buf
), irfile
);
217 (void) fgets(buf
, sizeof(buf
), irfile
);
219 if (add_symbols
== NULL
)
221 fprintf(stderr
, "tv_add_symbols interface missing\n");
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);
231 while (ftell(irfile
) < end_offset
232 && fgets(buf
, sizeof(buf
), irfile
) != NULL
)
234 parse_readelf_line(buf
, &info
);
236 /* Ignore local symbols. */
237 if (strncmp(info
.bind
, "LOCAL", 5) == 0)
240 weak
= strncmp(info
.bind
, "WEAK", 4) == 0;
241 if (strncmp(info
.sect
, "UND", 3) == 0)
242 def
= weak
? LDPK_WEAKUNDEF
: LDPK_UNDEF
;
243 else if (strncmp(info
.sect
, "COM", 3) == 0)
246 def
= weak
? LDPK_WEAKDEF
: LDPK_DEF
;
248 if (strncmp(info
.vis
, "INTERNAL", 8) == 0)
250 else if (strncmp(info
.vis
, "HIDDEN", 6) == 0)
252 else if (strncmp(info
.vis
, "PROTECTED", 9) == 0)
253 vis
= LDPV_PROTECTED
;
257 /* If the symbol is listed in the options list, special-case
258 it as a comdat symbol. */
260 for (i
= 0; i
< nopts
; ++i
)
262 if (info
.name
!= NULL
&& strcmp(info
.name
, opts
[i
]) == 0)
269 if (nsyms
>= maxsyms
)
271 syms
= (struct ld_plugin_symbol
*)
272 realloc(syms
, sizeof(struct ld_plugin_symbol
) * maxsyms
* 2);
278 if (info
.name
== NULL
)
279 syms
[nsyms
].name
= NULL
;
282 len
= strlen(info
.name
);
283 syms
[nsyms
].name
= malloc(len
+ 1);
284 strncpy(syms
[nsyms
].name
, info
.name
, len
+ 1);
286 syms
[nsyms
].version
= NULL
;
287 syms
[nsyms
].def
= def
;
288 syms
[nsyms
].visibility
= vis
;
289 syms
[nsyms
].size
= info
.size
;
290 syms
[nsyms
].comdat_key
= is_comdat
? syms
[nsyms
].name
: NULL
;
291 syms
[nsyms
].resolution
= LDPR_UNKNOWN
;
295 claimed_file
= (struct claimed_file
*) malloc(sizeof(struct claimed_file
));
296 if (claimed_file
== NULL
)
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
;
307 last_claimed_file
->next
= claimed_file
;
308 last_claimed_file
= claimed_file
;
310 (*message
)(LDPL_INFO
, "%s: claiming file, adding %d symbols",
314 (*add_symbols
)(file
->handle
, nsyms
, syms
);
320 enum ld_plugin_status
321 all_symbols_read_hook(void)
325 struct claimed_file
* claimed_file
;
326 struct ld_plugin_input_file file
;
329 struct sym_info info
;
333 const char* filename
;
335 (*message
)(LDPL_INFO
, "all symbols read hook called");
337 if (get_symbols
== NULL
)
339 fprintf(stderr
, "tv_get_symbols interface missing\n");
343 for (claimed_file
= first_claimed_file
;
344 claimed_file
!= NULL
;
345 claimed_file
= claimed_file
->next
)
347 (*get_symbols
)(claimed_file
->handle
, claimed_file
->nsyms
,
350 for (i
= 0; i
< claimed_file
->nsyms
; ++i
)
352 switch (claimed_file
->syms
[i
].resolution
)
360 case LDPR_PREVAILING_DEF
:
361 res
= "PREVAILING_DEF_REG";
363 case LDPR_PREVAILING_DEF_IRONLY
:
364 res
= "PREVAILING_DEF_IRONLY";
366 case LDPR_PREEMPTED_REG
:
367 res
= "PREEMPTED_REG";
369 case LDPR_PREEMPTED_IR
:
370 res
= "PREEMPTED_IR";
372 case LDPR_RESOLVED_IR
:
375 case LDPR_RESOLVED_EXEC
:
376 res
= "RESOLVED_EXEC";
378 case LDPR_RESOLVED_DYN
:
379 res
= "RESOLVED_DYN";
385 (*message
)(LDPL_INFO
, "%s: %s: %s", claimed_file
->name
,
386 claimed_file
->syms
[i
].name
, res
);
390 if (add_input_file
== NULL
)
392 fprintf(stderr
, "tv_add_input_file interface missing\n");
395 if (get_input_file
== NULL
)
397 fprintf(stderr
, "tv_get_input_file interface missing\n");
400 if (release_input_file
== NULL
)
402 fprintf(stderr
, "tv_release_input_file interface missing\n");
406 for (claimed_file
= first_claimed_file
;
407 claimed_file
!= NULL
;
408 claimed_file
= claimed_file
->next
)
410 (*get_input_file
) (claimed_file
->handle
, &file
);
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)
419 fprintf(stderr
, "%s: can't re-read original input file\n",
424 /* Skip the two header lines. */
425 (void) fgets(buf
, sizeof(buf
), irfile
);
426 (void) fgets(buf
, sizeof(buf
), irfile
);
429 while (ftell(irfile
) < end_offset
430 && fgets(buf
, sizeof(buf
), irfile
) != NULL
)
432 parse_readelf_line(buf
, &info
);
434 /* Look for file name. */
435 if (strncmp(info
.type
, "FILE", 4) == 0)
437 len
= strlen(info
.name
);
439 strncpy(p
, info
.name
, len
+ 1);
445 (*release_input_file
) (claimed_file
->handle
);
447 if (filename
== NULL
)
448 filename
= claimed_file
->name
;
450 if (claimed_file
->nsyms
== 0)
453 if (strlen(filename
) >= sizeof(buf
))
455 (*message
)(LDPL_FATAL
, "%s: filename too long", filename
);
458 strcpy(buf
, filename
);
459 p
= strrchr(buf
, '.');
461 || (strcmp(p
, ".syms") != 0
462 && strcmp(p
, ".c") != 0
463 && strcmp(p
, ".cc") != 0))
465 (*message
)(LDPL_FATAL
, "%s: filename has unknown suffix",
471 (*message
)(LDPL_INFO
, "%s: adding new input file", buf
);
472 (*add_input_file
)(buf
);
478 enum ld_plugin_status
481 (*message
)(LDPL_INFO
, "cleanup hook called");
486 parse_readelf_line(char* p
, struct sym_info
* info
)
493 p
+= strcspn(p
, " ");
497 p
+= strcspn(p
, " ");
501 info
->size
= atoi(p
);
502 p
+= strcspn(p
, " ");
507 p
+= strcspn(p
, " ");
512 p
+= strcspn(p
, " ");
515 /* Visibility field. */
517 p
+= strcspn(p
, " ");
522 p
+= strcspn(p
, " ");
526 /* FIXME: Look for version. */
530 else if (p
[len
-1] == '\n')