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