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