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