testplug.c revision 1.1.1.10 1 /* Test plugin for the GNU linker.
2 Copyright (C) 2010-2026 Free Software Foundation, Inc.
3
4 This file is part of the GNU Binutils.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19 MA 02110-1301, USA. */
20
21 #include "sysdep.h"
22 #include "bfd.h"
23 #include "plugin-api.h"
24 /* For ARRAY_SIZE macro only - we don't link the library itself. */
25 #include "libiberty.h"
26
27 #include <ctype.h> /* For isdigit. */
28
29 extern enum ld_plugin_status onload (struct ld_plugin_tv *tv);
30 static enum ld_plugin_status onclaim_file (const struct ld_plugin_input_file *file,
31 int *claimed);
32 static enum ld_plugin_status onall_symbols_read (void);
33 static enum ld_plugin_status oncleanup (void);
34
35 /* Helper for calling plugin api message function. */
36 #define TV_MESSAGE if (tv_message) (*tv_message)
37
38 /* Struct for recording files to claim / files claimed. */
39 typedef struct claim_file
40 {
41 struct claim_file *next;
42 struct ld_plugin_input_file file;
43 bool claimed;
44 struct ld_plugin_symbol *symbols;
45 int n_syms_allocated;
46 int n_syms_used;
47 } claim_file_t;
48
49 /* Types of things that can be added at all symbols read time. */
50 typedef enum addfile_enum
51 {
52 ADD_FILE,
53 ADD_LIB,
54 ADD_DIR
55 } addfile_enum_t;
56
57 /* Struct for recording files to add to final link. */
58 typedef struct add_file
59 {
60 struct add_file *next;
61 const char *name;
62 addfile_enum_t type;
63 } add_file_t;
64
65 /* Helper macro for defining array of transfer vector tags and names. */
66 #define ADDENTRY(tag) { tag, #tag }
67
68 /* Struct for looking up human-readable versions of tag names. */
69 typedef struct tag_name
70 {
71 enum ld_plugin_tag tag;
72 const char *name;
73 } tag_name_t;
74
75 /* Array of all known tags and their names. */
76 static const tag_name_t tag_names[] =
77 {
78 ADDENTRY(LDPT_NULL),
79 ADDENTRY(LDPT_API_VERSION),
80 ADDENTRY(LDPT_GOLD_VERSION),
81 ADDENTRY(LDPT_LINKER_OUTPUT),
82 ADDENTRY(LDPT_OPTION),
83 ADDENTRY(LDPT_REGISTER_CLAIM_FILE_HOOK),
84 ADDENTRY(LDPT_REGISTER_CLAIM_FILE_HOOK_V2),
85 ADDENTRY(LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK),
86 ADDENTRY(LDPT_REGISTER_CLEANUP_HOOK),
87 ADDENTRY(LDPT_ADD_SYMBOLS),
88 ADDENTRY(LDPT_GET_SYMBOLS),
89 ADDENTRY(LDPT_GET_SYMBOLS_V2),
90 ADDENTRY(LDPT_ADD_INPUT_FILE),
91 ADDENTRY(LDPT_MESSAGE),
92 ADDENTRY(LDPT_GET_INPUT_FILE),
93 ADDENTRY(LDPT_GET_VIEW),
94 ADDENTRY(LDPT_RELEASE_INPUT_FILE),
95 ADDENTRY(LDPT_ADD_INPUT_LIBRARY),
96 ADDENTRY(LDPT_OUTPUT_NAME),
97 ADDENTRY(LDPT_SET_EXTRA_LIBRARY_PATH),
98 ADDENTRY(LDPT_GNU_LD_VERSION)
99 };
100
101 /* Function pointers to cache hooks passed at onload time. */
102 static ld_plugin_register_claim_file tv_register_claim_file = 0;
103 static ld_plugin_register_claim_file_v2 tv_register_claim_file_v2 = 0;
104 static ld_plugin_register_all_symbols_read tv_register_all_symbols_read = 0;
105 static ld_plugin_register_cleanup tv_register_cleanup = 0;
106 static ld_plugin_add_symbols tv_add_symbols = 0;
107 static ld_plugin_get_symbols tv_get_symbols = 0;
108 static ld_plugin_get_symbols tv_get_symbols_v2 = 0;
109 static ld_plugin_add_input_file tv_add_input_file = 0;
110 static ld_plugin_message tv_message = 0;
111 static ld_plugin_get_input_file tv_get_input_file = 0;
112 static ld_plugin_get_view tv_get_view = 0;
113 static ld_plugin_release_input_file tv_release_input_file = 0;
114 static ld_plugin_add_input_library tv_add_input_library = 0;
115 static ld_plugin_set_extra_library_path tv_set_extra_library_path = 0;
116
117 /* Other cached info from the transfer vector. */
118 static enum ld_plugin_output_file_type linker_output;
119 static const char *output_name;
120
121 /* Behaviour control flags set by plugin options. */
122 static enum ld_plugin_status onload_ret = LDPS_OK;
123 static enum ld_plugin_status claim_file_ret = LDPS_OK;
124 static enum ld_plugin_status all_symbols_read_ret = LDPS_OK;
125 static enum ld_plugin_status cleanup_ret = LDPS_OK;
126 static bool register_claimfile_hook = false;
127 static bool register_allsymbolsread_hook = false;
128 static bool register_cleanup_hook = false;
129 static bool dumpresolutions = false;
130
131 /* The master list of all claimable/claimed files. */
132 static claim_file_t *claimfiles_list = NULL;
133
134 /* We keep a tail pointer for easy linking on the end. */
135 static claim_file_t **claimfiles_tail_chain_ptr = &claimfiles_list;
136
137 /* The last claimed file added to the list, for receiving syms. */
138 static claim_file_t *last_claimfile = NULL;
139
140 /* The master list of all files to add to the final link. */
141 static add_file_t *addfiles_list = NULL;
142
143 /* We keep a tail pointer for easy linking on the end. */
144 static add_file_t **addfiles_tail_chain_ptr = &addfiles_list;
145
146 /* Number of bytes read in claim file before deciding if the file can be
147 claimed. */
148 static int bytes_to_read_before_claim = 0;
149
150 /* Add a new claimfile on the end of the chain. */
151 static enum ld_plugin_status
152 record_claim_file (const char *file)
153 {
154 claim_file_t *newfile;
155
156 newfile = malloc (sizeof *newfile);
157 if (!newfile)
158 return LDPS_ERR;
159 memset (newfile, 0, sizeof *newfile);
160 /* Only setup for now is remembering the name to look for. */
161 newfile->file.name = file;
162 /* Chain it on the end of the list. */
163 *claimfiles_tail_chain_ptr = newfile;
164 claimfiles_tail_chain_ptr = &newfile->next;
165 /* Record it as active for receiving symbols to register. */
166 last_claimfile = newfile;
167 return LDPS_OK;
168 }
169
170 /* How many bytes to read before claiming (or not) an input file. */
171 static enum ld_plugin_status
172 record_read_length (const char *length)
173 {
174 const char *tmp;
175
176 tmp = length;
177 while (*tmp != '\0' && isdigit (*tmp))
178 ++tmp;
179 if (*tmp != '\0' || *length == '\0')
180 return LDPS_ERR;
181
182 bytes_to_read_before_claim = atoi (length);
183 return LDPS_OK;
184 }
185
186 /* Add a new addfile on the end of the chain. */
187 static enum ld_plugin_status
188 record_add_file (const char *file, addfile_enum_t type)
189 {
190 add_file_t *newfile;
191
192 newfile = malloc (sizeof *newfile);
193 if (!newfile)
194 return LDPS_ERR;
195 newfile->next = NULL;
196 newfile->name = file;
197 newfile->type = type;
198 /* Chain it on the end of the list. */
199 *addfiles_tail_chain_ptr = newfile;
200 addfiles_tail_chain_ptr = &newfile->next;
201 return LDPS_OK;
202 }
203
204 /* Parse a command-line argument string into a symbol definition.
205 Symbol-strings follow the colon-separated format:
206 NAME:VERSION:def:vis:size:COMDATKEY
207 where the fields in capitals are strings and those in lower
208 case are integers. We don't allow to specify a resolution as
209 doing so is not meaningful when calling the add symbols hook. */
210 static enum ld_plugin_status
211 parse_symdefstr (const char *str, struct ld_plugin_symbol *sym)
212 {
213 int n;
214 long long size;
215 const char *colon1, *colon2, *colon5;
216
217 /* Locate the colons separating the first two strings. */
218 colon1 = strchr (str, ':');
219 if (!colon1)
220 return LDPS_ERR;
221 colon2 = strchr (colon1+1, ':');
222 if (!colon2)
223 return LDPS_ERR;
224 /* Name must not be empty (version may be). */
225 if (colon1 == str)
226 return LDPS_ERR;
227
228 /* The fifth colon and trailing comdat key string are optional,
229 but the intermediate ones must all be present. */
230 colon5 = strchr (colon2+1, ':'); /* Actually only third so far. */
231 if (!colon5)
232 return LDPS_ERR;
233 colon5 = strchr (colon5+1, ':'); /* Hopefully fourth now. */
234 if (!colon5)
235 return LDPS_ERR;
236 colon5 = strchr (colon5+1, ':'); /* Optional fifth now. */
237
238 /* Finally we'll use sscanf to parse the numeric fields, then
239 we'll split out the strings which we need to allocate separate
240 storage for anyway so that we can add nul termination. */
241 n = sscanf (colon2 + 1, "%hhi:%i:%lli", &sym->def, &sym->visibility, &size);
242 if (n != 3)
243 return LDPS_ERR;
244
245 /* Parsed successfully, so allocate strings and fill out fields. */
246 sym->size = size;
247 sym->unused = 0;
248 sym->section_kind = 0;
249 sym->symbol_type = 0;
250 sym->resolution = LDPR_UNKNOWN;
251 sym->name = malloc (colon1 - str + 1);
252 if (!sym->name)
253 return LDPS_ERR;
254 memcpy (sym->name, str, colon1 - str);
255 sym->name[colon1 - str] = '\0';
256 if (colon2 > (colon1 + 1))
257 {
258 sym->version = malloc (colon2 - colon1);
259 if (!sym->version)
260 return LDPS_ERR;
261 memcpy (sym->version, colon1 + 1, colon2 - (colon1 + 1));
262 sym->version[colon2 - (colon1 + 1)] = '\0';
263 }
264 else
265 sym->version = NULL;
266 if (colon5 && colon5[1])
267 {
268 sym->comdat_key = malloc (strlen (colon5 + 1) + 1);
269 if (!sym->comdat_key)
270 return LDPS_ERR;
271 strcpy (sym->comdat_key, colon5 + 1);
272 }
273 else
274 sym->comdat_key = 0;
275 return LDPS_OK;
276 }
277
278 /* Record a symbol to be added for the last-added claimfile. */
279 static enum ld_plugin_status
280 record_claimed_file_symbol (const char *symdefstr)
281 {
282 struct ld_plugin_symbol sym;
283
284 /* Can't add symbols except as belonging to claimed files. */
285 if (!last_claimfile)
286 return LDPS_ERR;
287
288 /* If string doesn't parse correctly, give an error. */
289 if (parse_symdefstr (symdefstr, &sym) != LDPS_OK)
290 return LDPS_ERR;
291
292 /* Check for enough space, resize array if needed, and add it. */
293 if (last_claimfile->n_syms_allocated == last_claimfile->n_syms_used)
294 {
295 int new_n_syms = last_claimfile->n_syms_allocated
296 ? 2 * last_claimfile->n_syms_allocated
297 : 10;
298 last_claimfile->symbols = realloc (last_claimfile->symbols,
299 new_n_syms * sizeof *last_claimfile->symbols);
300 if (!last_claimfile->symbols)
301 return LDPS_ERR;
302 last_claimfile->n_syms_allocated = new_n_syms;
303 }
304 last_claimfile->symbols[last_claimfile->n_syms_used++] = sym;
305
306 return LDPS_OK;
307 }
308
309 /* Records the status to return from one of the registered hooks. */
310 static enum ld_plugin_status
311 set_ret_val (const char *whichval, enum ld_plugin_status retval)
312 {
313 if (!strcmp ("onload", whichval))
314 onload_ret = retval;
315 else if (!strcmp ("claimfile", whichval))
316 claim_file_ret = retval;
317 else if (!strcmp ("allsymbolsread", whichval))
318 all_symbols_read_ret = retval;
319 else if (!strcmp ("cleanup", whichval))
320 cleanup_ret = retval;
321 else
322 return LDPS_ERR;
323 return LDPS_OK;
324 }
325
326 /* Records hooks which should be registered. */
327 static enum ld_plugin_status
328 set_register_hook (const char *whichhook, bool yesno)
329 {
330 if (!strcmp ("claimfile", whichhook))
331 register_claimfile_hook = yesno;
332 else if (!strcmp ("allsymbolsread", whichhook))
333 register_allsymbolsread_hook = yesno;
334 else if (!strcmp ("cleanup", whichhook))
335 register_cleanup_hook = yesno;
336 else
337 return LDPS_ERR;
338 return LDPS_OK;
339 }
340
341 /* Determine type of plugin option and pass to individual parsers. */
342 static enum ld_plugin_status
343 parse_option (const char *opt)
344 {
345 if (!strncmp ("fail", opt, 4))
346 return set_ret_val (opt + 4, LDPS_ERR);
347 else if (!strncmp ("pass", opt, 4))
348 return set_ret_val (opt + 4, LDPS_OK);
349 else if (!strncmp ("register", opt, 8))
350 return set_register_hook (opt + 8, true);
351 else if (!strncmp ("noregister", opt, 10))
352 return set_register_hook (opt + 10, false);
353 else if (!strncmp ("claim:", opt, 6))
354 return record_claim_file (opt + 6);
355 else if (!strncmp ("read:", opt, 5))
356 return record_read_length (opt + 5);
357 else if (!strncmp ("sym:", opt, 4))
358 return record_claimed_file_symbol (opt + 4);
359 else if (!strncmp ("add:", opt, 4))
360 return record_add_file (opt + 4, ADD_FILE);
361 else if (!strncmp ("lib:", opt, 4))
362 return record_add_file (opt + 4, ADD_LIB);
363 else if (!strncmp ("dir:", opt, 4))
364 return record_add_file (opt + 4, ADD_DIR);
365 else if (!strcmp ("dumpresolutions", opt))
366 dumpresolutions = true;
367 else
368 return LDPS_ERR;
369 return LDPS_OK;
370 }
371
372 /* Output contents of transfer vector array entry in human-readable form. */
373 static void
374 dump_tv_tag (size_t n, struct ld_plugin_tv *tv)
375 {
376 size_t tag;
377 char unknownbuf[40];
378 const char *name;
379
380 for (tag = 0; tag < ARRAY_SIZE (tag_names); tag++)
381 if (tag_names[tag].tag == tv->tv_tag)
382 break;
383 sprintf (unknownbuf, "unknown tag #%d", tv->tv_tag);
384 name = (tag < ARRAY_SIZE (tag_names)) ? tag_names[tag].name : unknownbuf;
385 switch (tv->tv_tag)
386 {
387 case LDPT_OPTION:
388 case LDPT_OUTPUT_NAME:
389 TV_MESSAGE (LDPL_INFO, "tv[%d]: %s '%s'", n, name,
390 tv->tv_u.tv_string);
391 break;
392 case LDPT_REGISTER_CLAIM_FILE_HOOK:
393 case LDPT_REGISTER_CLAIM_FILE_HOOK_V2:
394 case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK:
395 case LDPT_REGISTER_CLEANUP_HOOK:
396 case LDPT_ADD_SYMBOLS:
397 case LDPT_GET_SYMBOLS:
398 case LDPT_GET_SYMBOLS_V2:
399 case LDPT_ADD_INPUT_FILE:
400 case LDPT_MESSAGE:
401 case LDPT_GET_INPUT_FILE:
402 case LDPT_GET_VIEW:
403 case LDPT_RELEASE_INPUT_FILE:
404 case LDPT_ADD_INPUT_LIBRARY:
405 case LDPT_SET_EXTRA_LIBRARY_PATH:
406 TV_MESSAGE (LDPL_INFO, "tv[%d]: %s func@0x%p", n, name,
407 (void *)(tv->tv_u.tv_message));
408 break;
409 case LDPT_NULL:
410 case LDPT_API_VERSION:
411 case LDPT_GOLD_VERSION:
412 case LDPT_LINKER_OUTPUT:
413 case LDPT_GNU_LD_VERSION:
414 default:
415 TV_MESSAGE (LDPL_INFO, "tv[%d]: %s value %W (%d)", n, name,
416 (bfd_vma)tv->tv_u.tv_val, tv->tv_u.tv_val);
417 break;
418 }
419 }
420
421 /* Handle/record information received in a transfer vector entry. */
422 static enum ld_plugin_status
423 parse_tv_tag (struct ld_plugin_tv *tv)
424 {
425 #define SETVAR(x) x = tv->tv_u.x
426 switch (tv->tv_tag)
427 {
428 case LDPT_OPTION:
429 return parse_option (tv->tv_u.tv_string);
430 case LDPT_NULL:
431 case LDPT_GOLD_VERSION:
432 case LDPT_GNU_LD_VERSION:
433 case LDPT_API_VERSION:
434 default:
435 break;
436 case LDPT_OUTPUT_NAME:
437 output_name = tv->tv_u.tv_string;
438 break;
439 case LDPT_LINKER_OUTPUT:
440 linker_output = tv->tv_u.tv_val;
441 break;
442 case LDPT_REGISTER_CLAIM_FILE_HOOK:
443 SETVAR(tv_register_claim_file);
444 break;
445 case LDPT_REGISTER_CLAIM_FILE_HOOK_V2:
446 SETVAR(tv_register_claim_file_v2);
447 break;
448 case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK:
449 SETVAR(tv_register_all_symbols_read);
450 break;
451 case LDPT_REGISTER_CLEANUP_HOOK:
452 SETVAR(tv_register_cleanup);
453 break;
454 case LDPT_ADD_SYMBOLS:
455 SETVAR(tv_add_symbols);
456 break;
457 case LDPT_GET_SYMBOLS:
458 SETVAR(tv_get_symbols);
459 break;
460 case LDPT_GET_SYMBOLS_V2:
461 tv_get_symbols_v2 = tv->tv_u.tv_get_symbols;
462 break;
463 case LDPT_ADD_INPUT_FILE:
464 SETVAR(tv_add_input_file);
465 break;
466 case LDPT_MESSAGE:
467 SETVAR(tv_message);
468 break;
469 case LDPT_GET_INPUT_FILE:
470 SETVAR(tv_get_input_file);
471 break;
472 case LDPT_GET_VIEW:
473 SETVAR(tv_get_view);
474 break;
475 case LDPT_RELEASE_INPUT_FILE:
476 SETVAR(tv_release_input_file);
477 break;
478 case LDPT_ADD_INPUT_LIBRARY:
479 SETVAR(tv_add_input_library);
480 break;
481 case LDPT_SET_EXTRA_LIBRARY_PATH:
482 SETVAR(tv_set_extra_library_path);
483 break;
484 }
485 #undef SETVAR
486 return LDPS_OK;
487 }
488
489 /* Record any useful information in transfer vector entry and display
490 it in human-readable form using the plugin API message() callback. */
491 enum ld_plugin_status
492 parse_and_dump_tv_tag (size_t n, struct ld_plugin_tv *tv)
493 {
494 enum ld_plugin_status rv = parse_tv_tag (tv);
495 dump_tv_tag (n, tv);
496 return rv;
497 }
498
499 /* Standard plugin API entry point. */
500 enum ld_plugin_status
501 onload (struct ld_plugin_tv *tv)
502 {
503 size_t n = 0;
504 enum ld_plugin_status rv;
505
506 /* This plugin does nothing but dump the tv array. It would
507 be an error if this function was called without one. */
508 if (!tv)
509 return LDPS_ERR;
510
511 /* First entry should always be LDPT_MESSAGE, letting us get
512 hold of it easily so we can send output straight away. */
513 if (tv[0].tv_tag == LDPT_MESSAGE)
514 tv_message = tv[0].tv_u.tv_message;
515
516 fflush (NULL);
517 TV_MESSAGE (LDPL_INFO, "Hello from testplugin.");
518
519 do
520 if ((rv = parse_and_dump_tv_tag (n++, tv)) != LDPS_OK)
521 return rv;
522 while ((tv++)->tv_tag != LDPT_NULL);
523
524 /* Register hooks only if instructed by options. */
525 if (register_claimfile_hook)
526 {
527 if (!tv_register_claim_file)
528 {
529 TV_MESSAGE (LDPL_FATAL, "No register_claim_file hook");
530 fflush (NULL);
531 return LDPS_ERR;
532 }
533 (*tv_register_claim_file) (onclaim_file);
534 }
535 if (register_allsymbolsread_hook)
536 {
537 if (!tv_register_all_symbols_read)
538 {
539 TV_MESSAGE (LDPL_FATAL, "No register_all_symbols_read hook");
540 fflush (NULL);
541 return LDPS_ERR;
542 }
543 (*tv_register_all_symbols_read) (onall_symbols_read);
544 }
545 if (register_cleanup_hook)
546 {
547 if (!tv_register_cleanup)
548 {
549 TV_MESSAGE (LDPL_FATAL, "No register_cleanup hook");
550 fflush (NULL);
551 return LDPS_ERR;
552 }
553 (*tv_register_cleanup) (oncleanup);
554 }
555 fflush (NULL);
556 return onload_ret;
557 }
558
559 /* Standard plugin API registerable hook. */
560 static enum ld_plugin_status
561 onclaim_file (const struct ld_plugin_input_file *file, int *claimed)
562 {
563 /* Possible read of some bytes out of the input file into a buffer. This
564 simulates a plugin that reads some file content in order to decide if
565 the file should be claimed or not. */
566 if (bytes_to_read_before_claim > 0)
567 {
568 char *buffer = malloc (bytes_to_read_before_claim);
569
570 if (buffer == NULL)
571 return LDPS_ERR;
572 if (read (file->fd, buffer, bytes_to_read_before_claim) < 0)
573 return LDPS_ERR;
574 free (buffer);
575 }
576
577 /* Let's see if we want to claim this file. */
578 claim_file_t *claimfile = claimfiles_list;
579 while (claimfile)
580 {
581 if (!strcmp (file->name, claimfile->file.name))
582 break;
583 claimfile = claimfile->next;
584 }
585
586 /* Inform the user/testsuite. */
587 TV_MESSAGE (LDPL_INFO, "hook called: claim_file %s [@%ld/%ld] %s",
588 file->name, (long)file->offset, (long)file->filesize,
589 claimfile ? "CLAIMED" : "not claimed");
590 fflush (NULL);
591
592 /* If we decided to claim it, record that fact, and add any symbols
593 that were defined for it by plugin options. */
594 *claimed = (claimfile != 0);
595 if (claimfile)
596 {
597 claimfile->claimed = true;
598 claimfile->file = *file;
599 if (claimfile->n_syms_used && !tv_add_symbols)
600 return LDPS_ERR;
601 else if (claimfile->n_syms_used)
602 return (*tv_add_symbols) (claimfile->file.handle,
603 claimfile->n_syms_used, claimfile->symbols);
604 }
605
606 return claim_file_ret;
607 }
608
609 /* Standard plugin API registerable hook. */
610 static enum ld_plugin_status
611 onall_symbols_read (void)
612 {
613 static const char *resolutions[] =
614 {
615 "LDPR_UNKNOWN",
616 "LDPR_UNDEF",
617 "LDPR_PREVAILING_DEF",
618 "LDPR_PREVAILING_DEF_IRONLY",
619 "LDPR_PREEMPTED_REG",
620 "LDPR_PREEMPTED_IR",
621 "LDPR_RESOLVED_IR",
622 "LDPR_RESOLVED_EXEC",
623 "LDPR_RESOLVED_DYN",
624 "LDPR_PREVAILING_DEF_IRONLY_EXP",
625 };
626 claim_file_t *claimfile = dumpresolutions ? claimfiles_list : NULL;
627 add_file_t *addfile = addfiles_list;
628 TV_MESSAGE (LDPL_INFO, "hook called: all symbols read.");
629 for ( ; claimfile; claimfile = claimfile->next)
630 {
631 enum ld_plugin_status rv;
632 int n;
633 if (claimfile->n_syms_used && !tv_get_symbols_v2)
634 return LDPS_ERR;
635 else if (!claimfile->n_syms_used)
636 continue;
637 rv = tv_get_symbols_v2 (claimfile->file.handle, claimfile->n_syms_used,
638 claimfile->symbols);
639 if (rv != LDPS_OK)
640 return rv;
641 for (n = 0; n < claimfile->n_syms_used; n++)
642 TV_MESSAGE (LDPL_INFO, "Sym: '%s%s%s' Resolution: %s",
643 claimfile->symbols[n].name,
644 claimfile->symbols[n].version ? "@" : "",
645 (claimfile->symbols[n].version
646 ? claimfile->symbols[n].version : ""),
647 resolutions[claimfile->symbols[n].resolution]);
648 }
649 for ( ; addfile ; addfile = addfile->next)
650 {
651 enum ld_plugin_status rv;
652 if (addfile->type == ADD_LIB && tv_add_input_library)
653 rv = (*tv_add_input_library) (addfile->name);
654 else if (addfile->type == ADD_FILE && tv_add_input_file)
655 rv = (*tv_add_input_file) (addfile->name);
656 else if (addfile->type == ADD_DIR && tv_set_extra_library_path)
657 rv = (*tv_set_extra_library_path) (addfile->name);
658 else
659 rv = LDPS_ERR;
660 if (rv != LDPS_OK)
661 return rv;
662 }
663 fflush (NULL);
664 return all_symbols_read_ret;
665 }
666
667 /* Standard plugin API registerable hook. */
668 static enum ld_plugin_status
669 oncleanup (void)
670 {
671 TV_MESSAGE (LDPL_INFO, "hook called: cleanup.");
672 fflush (NULL);
673 return cleanup_ret;
674 }
675