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