1 /* test_plugin.c -- simple linker plugin test
3 Copyright 2008 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
;
37 static struct claimed_file
* first_claimed_file
= NULL
;
38 static struct claimed_file
* last_claimed_file
= NULL
;
40 static ld_plugin_register_claim_file register_claim_file_hook
= NULL
;
41 static ld_plugin_register_all_symbols_read register_all_symbols_read_hook
= NULL
;
42 static ld_plugin_register_cleanup register_cleanup_hook
= NULL
;
43 static ld_plugin_add_symbols add_symbols
= NULL
;
44 static ld_plugin_get_symbols get_symbols
= NULL
;
45 static ld_plugin_add_input_file add_input_file
= NULL
;
46 static ld_plugin_message message
= NULL
;
50 static const char *opts
[MAXOPTS
];
53 enum ld_plugin_status
onload(struct ld_plugin_tv
*tv
);
54 enum ld_plugin_status
claim_file_hook(const struct ld_plugin_input_file
*file
,
56 enum ld_plugin_status
all_symbols_read_hook(void);
57 enum ld_plugin_status
cleanup_hook(void);
60 onload(struct ld_plugin_tv
*tv
)
62 struct ld_plugin_tv
*entry
;
67 for (entry
= tv
; entry
->tv_tag
!= LDPT_NULL
; ++entry
)
69 switch (entry
->tv_tag
)
71 case LDPT_API_VERSION
:
72 api_version
= entry
->tv_u
.tv_val
;
74 case LDPT_GOLD_VERSION
:
75 gold_version
= entry
->tv_u
.tv_val
;
77 case LDPT_LINKER_OUTPUT
:
81 opts
[nopts
++] = entry
->tv_u
.tv_string
;
83 case LDPT_REGISTER_CLAIM_FILE_HOOK
:
84 register_claim_file_hook
= entry
->tv_u
.tv_register_claim_file
;
86 case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK
:
87 register_all_symbols_read_hook
=
88 entry
->tv_u
.tv_register_all_symbols_read
;
90 case LDPT_REGISTER_CLEANUP_HOOK
:
91 register_cleanup_hook
= entry
->tv_u
.tv_register_cleanup
;
93 case LDPT_ADD_SYMBOLS
:
94 add_symbols
= entry
->tv_u
.tv_add_symbols
;
96 case LDPT_GET_SYMBOLS
:
97 get_symbols
= entry
->tv_u
.tv_get_symbols
;
99 case LDPT_ADD_INPUT_FILE
:
100 add_input_file
= entry
->tv_u
.tv_add_input_file
;
103 message
= entry
->tv_u
.tv_message
;
112 fprintf(stderr
, "tv_message interface missing\n");
116 if (register_claim_file_hook
== NULL
)
118 fprintf(stderr
, "tv_register_claim_file_hook interface missing\n");
122 if (register_all_symbols_read_hook
== NULL
)
124 fprintf(stderr
, "tv_register_all_symbols_read_hook interface missing\n");
128 if (register_cleanup_hook
== NULL
)
130 fprintf(stderr
, "tv_register_cleanup_hook interface missing\n");
134 (*message
)(LDPL_INFO
, "API version: %d", api_version
);
135 (*message
)(LDPL_INFO
, "gold version: %d", gold_version
);
137 for (i
= 0; i
< nopts
; ++i
)
138 (*message
)(LDPL_INFO
, "option: %s", opts
[i
]);
140 if ((*register_claim_file_hook
)(claim_file_hook
) != LDPS_OK
)
142 (*message
)(LDPL_ERROR
, "error registering claim file hook");
146 if ((*register_all_symbols_read_hook
)(all_symbols_read_hook
) != LDPS_OK
)
148 (*message
)(LDPL_ERROR
, "error registering all symbols read hook");
152 if ((*register_cleanup_hook
)(cleanup_hook
) != LDPS_OK
)
154 (*message
)(LDPL_ERROR
, "error registering cleanup hook");
161 enum ld_plugin_status
162 claim_file_hook (const struct ld_plugin_input_file
* file
, int* claimed
)
166 struct claimed_file
* claimed_file
;
167 struct ld_plugin_symbol
* syms
;
183 (*message
)(LDPL_INFO
,
184 "%s: claim file hook called (offset = %ld, size = %ld)",
185 file
->name
, (long)file
->offset
, (long)file
->filesize
);
187 /* Look for the beginning of output from readelf -s. */
188 irfile
= fdopen(file
->fd
, "r");
189 (void)fseek(irfile
, file
->offset
, SEEK_SET
);
190 len
= fread(buf
, 1, 13, irfile
);
191 if (len
< 13 || strncmp(buf
, "\nSymbol table", 13) != 0)
194 /* Skip the two header lines. */
195 (void) fgets(buf
, sizeof(buf
), irfile
);
196 (void) fgets(buf
, sizeof(buf
), irfile
);
198 if (add_symbols
== NULL
)
200 fprintf(stderr
, "tv_add_symbols interface missing\n");
204 /* Parse the output from readelf. The columns are:
205 Index Value Size Type Binding Visibility Section Name. */
206 syms
= (struct ld_plugin_symbol
*)malloc(sizeof(struct ld_plugin_symbol
) * 8);
210 while (fgets(buf
, sizeof(buf
), irfile
) != NULL
)
216 p
+= strcspn(p
, " ");
220 p
+= strcspn(p
, " ");
225 p
+= strcspn(p
, " ");
229 p
+= strcspn(p
, " ");
234 p
+= strcspn(p
, " ");
237 /* Visibility field. */
239 p
+= strcspn(p
, " ");
244 p
+= strcspn(p
, " ");
248 /* FIXME: Look for version. */
250 if (p
[len
-1] == '\n')
252 name
= malloc(len
+ 1);
253 strncpy(name
, p
, len
+ 1);
255 /* Ignore local symbols. */
256 if (strncmp(pbind
, "LOCAL", 5) == 0)
259 weak
= strncmp(pbind
, "WEAK", 4) == 0;
260 if (strncmp(psect
, "UND", 3) == 0)
261 def
= weak
? LDPK_WEAKUNDEF
: LDPK_UNDEF
;
262 else if (strncmp(psect
, "COM", 3) == 0)
265 def
= weak
? LDPK_WEAKDEF
: LDPK_DEF
;
267 if (strncmp(pvis
, "INTERNAL", 8) == 0)
269 else if (strncmp(pvis
, "HIDDEN", 6) == 0)
271 else if (strncmp(pvis
, "PROTECTED", 9) == 0)
272 vis
= LDPV_PROTECTED
;
276 /* If the symbol is listed in the options list, special-case
277 it as a comdat symbol. */
279 for (i
= 0; i
< nopts
; ++i
)
281 if (name
!= NULL
&& strcmp(name
, opts
[i
]) == 0)
288 if (nsyms
>= maxsyms
)
290 syms
= (struct ld_plugin_symbol
*)
291 realloc(syms
, sizeof(struct ld_plugin_symbol
) * maxsyms
* 2);
297 syms
[nsyms
].name
= name
;
298 syms
[nsyms
].version
= NULL
;
299 syms
[nsyms
].def
= def
;
300 syms
[nsyms
].visibility
= vis
;
301 syms
[nsyms
].size
= size
;
302 syms
[nsyms
].comdat_key
= is_comdat
? name
: NULL
;
303 syms
[nsyms
].resolution
= LDPR_UNKNOWN
;
307 claimed_file
= (struct claimed_file
*) malloc(sizeof(struct claimed_file
));
308 if (claimed_file
== NULL
)
311 claimed_file
->name
= file
->name
;
312 claimed_file
->handle
= file
->handle
;
313 claimed_file
->nsyms
= nsyms
;
314 claimed_file
->syms
= syms
;
315 claimed_file
->next
= NULL
;
316 if (last_claimed_file
== NULL
)
317 first_claimed_file
= claimed_file
;
319 last_claimed_file
->next
= claimed_file
;
320 last_claimed_file
= claimed_file
;
322 (*add_symbols
)(file
->handle
, nsyms
, syms
);
328 enum ld_plugin_status
329 all_symbols_read_hook(void)
333 struct claimed_file
* claimed_file
;
337 (*message
)(LDPL_INFO
, "all symbols read hook called");
339 if (get_symbols
== NULL
)
341 fprintf(stderr
, "tv_get_symbols interface missing\n");
345 for (claimed_file
= first_claimed_file
;
346 claimed_file
!= NULL
;
347 claimed_file
= claimed_file
->next
)
349 (*get_symbols
)(claimed_file
->handle
, claimed_file
->nsyms
,
351 for (i
= 0; i
< claimed_file
->nsyms
; ++i
)
353 switch (claimed_file
->syms
[i
].resolution
)
361 case LDPR_PREVAILING_DEF
:
362 res
= "PREVAILING_DEF_REG";
364 case LDPR_PREVAILING_DEF_IRONLY
:
365 res
= "PREVAILING_DEF_IRONLY";
367 case LDPR_PREEMPTED_REG
:
368 res
= "PREEMPTED_REG";
370 case LDPR_PREEMPTED_IR
:
371 res
= "PREEMPTED_IR";
373 case LDPR_RESOLVED_IR
:
376 case LDPR_RESOLVED_EXEC
:
377 res
= "RESOLVED_EXEC";
379 case LDPR_RESOLVED_DYN
:
380 res
= "RESOLVED_DYN";
386 (*message
)(LDPL_INFO
, "%s: %s: %s", claimed_file
->name
,
387 claimed_file
->syms
[i
].name
, res
);
391 if (add_input_file
== NULL
)
393 fprintf(stderr
, "tv_add_input_file interface missing\n");
397 for (claimed_file
= first_claimed_file
;
398 claimed_file
!= NULL
;
399 claimed_file
= claimed_file
->next
)
401 if (strlen(claimed_file
->name
) >= sizeof(buf
))
403 (*message
)(LDPL_FATAL
, "%s: filename too long", claimed_file
->name
);
406 strcpy(buf
, claimed_file
->name
);
407 p
= strrchr(buf
, '.');
408 if (p
== NULL
|| strcmp(p
, ".syms") != 0)
410 (*message
)(LDPL_FATAL
, "%s: filename must have '.syms' suffix",
416 (*add_input_file
)(buf
);
422 enum ld_plugin_status
425 (*message
)(LDPL_INFO
, "cleanup hook called");