1/* Test plugin for the GNU linker.  Check non-object IR file as well as
2   get_input_file, get_view, release_input_file and get_symbols interfaces.
3   Copyright (C) 2016-2017 Free Software Foundation, Inc.
4
5   This file is part of the GNU Binutils.
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 3 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20   MA 02110-1301, USA.  */
21
22#include "sysdep.h"
23#include "bfd.h"
24#include "plugin-api.h"
25#include "filenames.h"
26/* For ARRAY_SIZE macro only - we don't link the library itself.  */
27#include "libiberty.h"
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 = TRUE;
125static bfd_boolean register_allsymbolsread_hook = FALSE;
126static bfd_boolean register_cleanup_hook = FALSE;
127static bfd_boolean dumpresolutions = FALSE;
128static bfd_boolean allsymbolsread_silent = 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/* Add a new claimfile on the end of the chain.  */
146static enum ld_plugin_status
147record_claim_file (const char *file, off_t filesize)
148{
149  claim_file_t *newfile;
150
151  newfile = malloc (sizeof *newfile);
152  if (!newfile)
153    return LDPS_ERR;
154  memset (newfile, 0, sizeof *newfile);
155  /* Only setup for now is remembering the name to look for.  */
156  newfile->file.name = file;
157  newfile->file.filesize = filesize;
158  /* Chain it on the end of the list.  */
159  *claimfiles_tail_chain_ptr = newfile;
160  claimfiles_tail_chain_ptr = &newfile->next;
161  /* Record it as active for receiving symbols to register.  */
162  last_claimfile = newfile;
163  return LDPS_OK;
164}
165
166/* Add a new addfile on the end of the chain.  */
167static enum ld_plugin_status
168record_add_file (const char *file, addfile_enum_t type)
169{
170  add_file_t *newfile;
171
172  newfile = malloc (sizeof *newfile);
173  if (!newfile)
174    return LDPS_ERR;
175  newfile->next = NULL;
176  newfile->name = file;
177  newfile->type = type;
178  /* Chain it on the end of the list.  */
179  *addfiles_tail_chain_ptr = newfile;
180  addfiles_tail_chain_ptr = &newfile->next;
181  return LDPS_OK;
182}
183
184/* Parse a command-line argument string into a symbol definition.
185   Symbol-strings follow the colon-separated format:
186	NAME:VERSION:def:vis:size:COMDATKEY
187   where the fields in capitals are strings and those in lower
188   case are integers.  We don't allow to specify a resolution as
189   doing so is not meaningful when calling the add symbols hook.  */
190static enum ld_plugin_status
191parse_symdefstr (const char *str, struct ld_plugin_symbol *sym)
192{
193  int n;
194  long long size;
195  const char *colon1, *colon2, *colon5;
196
197  /* Locate the colons separating the first two strings.  */
198  colon1 = strchr (str, ':');
199  if (!colon1)
200    return LDPS_ERR;
201  colon2 = strchr (colon1+1, ':');
202  if (!colon2)
203    return LDPS_ERR;
204  /* Name must not be empty (version may be).  */
205  if (colon1 == str)
206    return LDPS_ERR;
207
208  /* The fifth colon and trailing comdat key string are optional,
209     but the intermediate ones must all be present.  */
210  colon5 = strchr (colon2+1, ':');	/* Actually only third so far.  */
211  if (!colon5)
212    return LDPS_ERR;
213  colon5 = strchr (colon5+1, ':');	/* Hopefully fourth now.  */
214  if (!colon5)
215    return LDPS_ERR;
216  colon5 = strchr (colon5+1, ':');	/* Optional fifth now.  */
217
218  /* Finally we'll use sscanf to parse the numeric fields, then
219     we'll split out the strings which we need to allocate separate
220     storage for anyway so that we can add nul termination.  */
221  n = sscanf (colon2 + 1, "%i:%i:%lli", &sym->def, &sym->visibility, &size);
222  if (n != 3)
223    return LDPS_ERR;
224
225  /* Parsed successfully, so allocate strings and fill out fields.  */
226  sym->size = size;
227  sym->resolution = LDPR_UNKNOWN;
228  sym->name = malloc (colon1 - str + 1);
229  if (!sym->name)
230    return LDPS_ERR;
231  memcpy (sym->name, str, colon1 - str);
232  sym->name[colon1 - str] = '\0';
233  if (colon2 > (colon1 + 1))
234    {
235      sym->version = malloc (colon2 - colon1);
236      if (!sym->version)
237	return LDPS_ERR;
238      memcpy (sym->version, colon1 + 1, colon2 - (colon1 + 1));
239      sym->version[colon2 - (colon1 + 1)] = '\0';
240    }
241  else
242    sym->version = NULL;
243  if (colon5 && colon5[1])
244    {
245      sym->comdat_key = malloc (strlen (colon5 + 1) + 1);
246      if (!sym->comdat_key)
247	return LDPS_ERR;
248      strcpy (sym->comdat_key, colon5 + 1);
249    }
250  else
251    sym->comdat_key = 0;
252  return LDPS_OK;
253}
254
255/* Record a symbol to be added for the last-added claimfile.  */
256static enum ld_plugin_status
257record_claimed_file_symbol (const char *symdefstr)
258{
259  struct ld_plugin_symbol sym;
260
261  /* Can't add symbols except as belonging to claimed files.  */
262  if (!last_claimfile)
263    return LDPS_ERR;
264
265  /* If string doesn't parse correctly, give an error.  */
266  if (parse_symdefstr (symdefstr, &sym) != LDPS_OK)
267    return LDPS_ERR;
268
269  /* Check for enough space, resize array if needed, and add it.  */
270  if (last_claimfile->n_syms_allocated == last_claimfile->n_syms_used)
271    {
272      int new_n_syms = last_claimfile->n_syms_allocated
273			? 2 * last_claimfile->n_syms_allocated
274			: 10;
275      last_claimfile->symbols = realloc (last_claimfile->symbols,
276			new_n_syms * sizeof *last_claimfile->symbols);
277      if (!last_claimfile->symbols)
278	return LDPS_ERR;
279      last_claimfile->n_syms_allocated = new_n_syms;
280    }
281  last_claimfile->symbols[last_claimfile->n_syms_used++] = sym;
282
283  return LDPS_OK;
284}
285
286/* Records the status to return from one of the registered hooks.  */
287static enum ld_plugin_status
288set_ret_val (const char *whichval, enum ld_plugin_status retval)
289{
290  if (!strcmp ("onload", whichval))
291    onload_ret = retval;
292  else if (!strcmp ("claimfile", whichval))
293    claim_file_ret = retval;
294  else if (!strcmp ("allsymbolsread", whichval))
295    all_symbols_read_ret = retval;
296  else if (!strcmp ("cleanup", whichval))
297    cleanup_ret = retval;
298  else
299    return LDPS_ERR;
300  return LDPS_OK;
301}
302
303/* Records hooks which should be registered.  */
304static enum ld_plugin_status
305set_register_hook (const char *whichhook, bfd_boolean yesno)
306{
307  if (!strcmp ("claimfile", whichhook))
308    register_claimfile_hook = yesno;
309  else if (!strcmp ("allsymbolsread", whichhook))
310    register_allsymbolsread_hook = yesno;
311  else if (!strcmp ("allsymbolsreadsilent", whichhook))
312    {
313      register_allsymbolsread_hook = yesno;
314      allsymbolsread_silent = TRUE;
315    }
316  else if (!strcmp ("cleanup", whichhook))
317    register_cleanup_hook = yesno;
318  else
319    return LDPS_ERR;
320  return LDPS_OK;
321}
322
323/* Determine type of plugin option and pass to individual parsers.  */
324static enum ld_plugin_status
325parse_option (const char *opt)
326{
327  if (!strncmp ("fatal", opt, 5))
328    {
329      TV_MESSAGE (LDPL_FATAL, "Fatal error");
330      fflush (NULL);
331    }
332  else if (!strncmp ("error", opt, 5))
333    {
334      TV_MESSAGE (LDPL_ERROR, "Error");
335      fflush (NULL);
336    }
337  else if (!strncmp ("warning", opt, 7))
338    {
339      TV_MESSAGE (LDPL_WARNING, "Warning");
340      fflush (NULL);
341    }
342  else if (!strncmp ("fail", opt, 4))
343    return set_ret_val (opt + 4, LDPS_ERR);
344  else if (!strncmp ("pass", opt, 4))
345    return set_ret_val (opt + 4, LDPS_OK);
346  else if (!strncmp ("register", opt, 8))
347    return set_register_hook (opt + 8, TRUE);
348  else if (!strncmp ("noregister", opt, 10))
349    return set_register_hook (opt + 10, FALSE);
350  else if (!strncmp ("claim:", opt, 6))
351    return record_claim_file (opt + 6, 0);
352  else if (!strncmp ("sym:", opt, 4))
353    return record_claimed_file_symbol (opt + 4);
354  else if (!strncmp ("add:", opt, 4))
355    return record_add_file (opt + 4, ADD_FILE);
356  else if (!strncmp ("lib:", opt, 4))
357    return record_add_file (opt + 4, ADD_LIB);
358  else if (!strncmp ("dir:", opt, 4))
359    return record_add_file (opt + 4, ADD_DIR);
360  else if (!strcmp ("dumpresolutions", opt))
361    dumpresolutions = TRUE;
362  else
363    return LDPS_ERR;
364  return LDPS_OK;
365}
366
367/* Handle/record information received in a transfer vector entry.  */
368static enum ld_plugin_status
369parse_tv_tag (struct ld_plugin_tv *tv)
370{
371#define SETVAR(x) x = tv->tv_u.x
372  switch (tv->tv_tag)
373    {
374      case LDPT_OPTION:
375	return parse_option (tv->tv_u.tv_string);
376      case LDPT_NULL:
377      case LDPT_GOLD_VERSION:
378      case LDPT_GNU_LD_VERSION:
379      case LDPT_API_VERSION:
380      default:
381	break;
382      case LDPT_OUTPUT_NAME:
383	output_name = tv->tv_u.tv_string;
384	break;
385      case LDPT_LINKER_OUTPUT:
386	linker_output = tv->tv_u.tv_val;
387	break;
388      case LDPT_REGISTER_CLAIM_FILE_HOOK:
389	SETVAR(tv_register_claim_file);
390	break;
391      case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK:
392	SETVAR(tv_register_all_symbols_read);
393	break;
394      case LDPT_REGISTER_CLEANUP_HOOK:
395	SETVAR(tv_register_cleanup);
396	break;
397      case LDPT_ADD_SYMBOLS:
398	SETVAR(tv_add_symbols);
399	break;
400      case LDPT_GET_SYMBOLS:
401	SETVAR(tv_get_symbols);
402	break;
403      case LDPT_GET_SYMBOLS_V2:
404	tv_get_symbols_v2 = tv->tv_u.tv_get_symbols;
405	break;
406      case LDPT_ADD_INPUT_FILE:
407	SETVAR(tv_add_input_file);
408	break;
409      case LDPT_MESSAGE:
410	SETVAR(tv_message);
411	break;
412      case LDPT_GET_INPUT_FILE:
413	SETVAR(tv_get_input_file);
414	break;
415      case LDPT_GET_VIEW:
416	SETVAR(tv_get_view);
417	break;
418      case LDPT_RELEASE_INPUT_FILE:
419	SETVAR(tv_release_input_file);
420	break;
421      case LDPT_ADD_INPUT_LIBRARY:
422	SETVAR(tv_add_input_library);
423	break;
424      case LDPT_SET_EXTRA_LIBRARY_PATH:
425	SETVAR(tv_set_extra_library_path);
426	break;
427    }
428#undef SETVAR
429  return LDPS_OK;
430}
431
432/* Standard plugin API entry point.  */
433enum ld_plugin_status
434onload (struct ld_plugin_tv *tv)
435{
436  enum ld_plugin_status rv;
437
438  /* This plugin does nothing but dump the tv array.  It would
439     be an error if this function was called without one.  */
440  if (!tv)
441    return LDPS_ERR;
442
443  /* First entry should always be LDPT_MESSAGE, letting us get
444     hold of it easily so we can send output straight away.  */
445  if (tv[0].tv_tag == LDPT_MESSAGE)
446    tv_message = tv[0].tv_u.tv_message;
447
448  do
449    if ((rv = parse_tv_tag (tv)) != LDPS_OK)
450      return rv;
451  while ((tv++)->tv_tag != LDPT_NULL);
452
453  /* Register hooks only if instructed by options.  */
454  if (register_claimfile_hook)
455    {
456      if (!tv_register_claim_file)
457	{
458	  TV_MESSAGE (LDPL_FATAL, "No register_claim_file hook");
459	  fflush (NULL);
460	  return LDPS_ERR;
461	}
462      (*tv_register_claim_file) (onclaim_file);
463    }
464  if (register_allsymbolsread_hook)
465    {
466      if (!tv_register_all_symbols_read)
467	{
468	  TV_MESSAGE (LDPL_FATAL, "No register_all_symbols_read hook");
469	  fflush (NULL);
470	  return LDPS_ERR;
471	}
472      (*tv_register_all_symbols_read) (onall_symbols_read);
473    }
474  if (register_cleanup_hook)
475    {
476      if (!tv_register_cleanup)
477	{
478	  TV_MESSAGE (LDPL_FATAL, "No register_cleanup hook");
479	  fflush (NULL);
480	  return LDPS_ERR;
481	}
482      (*tv_register_cleanup) (oncleanup);
483    }
484
485  /* Claim testsuite/ld-plugin/pr20070b.c, standalone or in a library.
486     Its size must be SIZE_OF_PR20070B_C bytes.  */
487#define SIZE_OF_PR20070B_C	248
488  if (onload_ret == LDPS_OK
489      && (record_claim_file ("pr20070b.c", SIZE_OF_PR20070B_C) != LDPS_OK
490	  || record_claimed_file_symbol ("def::0:0:0") != LDPS_OK
491	  || record_claimed_file_symbol ("weakdef::1:0:0") != LDPS_OK
492	  || record_claimed_file_symbol ("undef::2:0:0") != LDPS_OK
493	  || record_claimed_file_symbol ("weakundef::3:0:0") != LDPS_OK
494	  || record_claimed_file_symbol ("common::4:0:0") != LDPS_OK
495	  || record_claim_file ("libpr20070.a", SIZE_OF_PR20070B_C) != LDPS_OK
496	  || record_claimed_file_symbol ("def::0:0:0") != LDPS_OK
497	  || record_claimed_file_symbol ("weakdef::1:0:0") != LDPS_OK
498	  || record_claimed_file_symbol ("undef::2:0:0") != LDPS_OK
499	  || record_claimed_file_symbol ("weakundef::3:0:0") != LDPS_OK
500	  || record_claimed_file_symbol ("common::4:0:0") != LDPS_OK))
501    onload_ret = LDPS_ERR;
502
503  return onload_ret;
504}
505
506char *
507xstrdup (const char *s)
508{
509  size_t len = strlen (s) + 1;
510  char *ret = malloc (len + 1);
511  return (char *) memcpy (ret, s, len);
512}
513
514/* Standard plugin API registerable hook.  */
515static enum ld_plugin_status
516onclaim_file (const struct ld_plugin_input_file *file, int *claimed)
517{
518  /* Let's see if we want to claim this file.  */
519  claim_file_t *claimfile = claimfiles_list;
520  size_t len = strlen (file->name);
521  char *name = xstrdup (file->name);
522  char *p = name + len;
523  bfd_boolean islib;
524
525  /* Only match the file name without the directory part.  */
526  islib = *p == 'a' && *(p - 1) == '.';
527  for (; p != name; p--)
528    if (IS_DIR_SEPARATOR (*p))
529      {
530	p++;
531	break;
532      }
533
534  while (claimfile)
535    {
536      /* Claim the file only if the file name and size match and don't
537	 match the whole library.  */
538      if (!strcmp (p, claimfile->file.name)
539	  && claimfile->file.filesize == file->filesize
540	  && (!islib || file->offset != 0))
541	break;
542      claimfile = claimfile->next;
543    }
544
545  free (name);
546
547  /* If we decided to claim it, record that fact, and add any symbols
548     that were defined for it by plugin options.  */
549  *claimed = (claimfile != 0);
550  if (claimfile)
551    {
552      claimfile->claimed = TRUE;
553      claimfile->file = *file;
554      if (claimfile->n_syms_used && !tv_add_symbols)
555	return LDPS_ERR;
556      else if (claimfile->n_syms_used)
557	return (*tv_add_symbols) (claimfile->file.handle,
558				claimfile->n_syms_used, claimfile->symbols);
559    }
560
561  return claim_file_ret;
562}
563
564/* Standard plugin API registerable hook.  */
565static enum ld_plugin_status
566onall_symbols_read (void)
567{
568  static const char *resolutions[] =
569    {
570      "LDPR_UNKNOWN",
571      "LDPR_UNDEF",
572      "LDPR_PREVAILING_DEF",
573      "LDPR_PREVAILING_DEF_IRONLY",
574      "LDPR_PREEMPTED_REG",
575      "LDPR_PREEMPTED_IR",
576      "LDPR_RESOLVED_IR",
577      "LDPR_RESOLVED_EXEC",
578      "LDPR_RESOLVED_DYN",
579      "LDPR_PREVAILING_DEF_IRONLY_EXP",
580    };
581  claim_file_t *claimfile = dumpresolutions ? claimfiles_list : NULL;
582  add_file_t *addfile = addfiles_list;
583  struct ld_plugin_input_file file;
584  const void *view;
585  char buffer[30];
586  int fd;
587  char *filename;
588  if (! allsymbolsread_silent)
589    TV_MESSAGE (LDPL_INFO, "hook called: all symbols read.");
590  for ( ; claimfile; claimfile = claimfile->next)
591    {
592      enum ld_plugin_status rv;
593      int n;
594      if (claimfile->n_syms_used && !tv_get_symbols_v2)
595	return LDPS_ERR;
596      else if (!claimfile->n_syms_used)
597        continue;
598      else if (!claimfile->file.handle)
599        continue;
600      rv = tv_get_input_file (claimfile->file.handle, &file);
601      if (rv != LDPS_OK)
602	return rv;
603      TV_MESSAGE (LDPL_INFO, "Input: %s (%s)", file.name,
604		  claimfile->file.name);
605      rv = tv_get_view (claimfile->file.handle, &view);
606      if (rv != LDPS_OK)
607	return rv;
608#define EXPECTED_VIEW "/* The first line of this file must match the expectation of"
609#define EXPECTED_VIEW_LENGTH (sizeof (EXPECTED_VIEW) - 1)
610      if (file.filesize != SIZE_OF_PR20070B_C
611	  || SIZE_OF_PR20070B_C < EXPECTED_VIEW_LENGTH
612	  || memcmp (view, EXPECTED_VIEW, EXPECTED_VIEW_LENGTH) != 0)
613	{
614	  char result[EXPECTED_VIEW_LENGTH + 1];
615	  memcpy (result, view, sizeof (result));
616	  result[EXPECTED_VIEW_LENGTH] = '\0';
617	  TV_MESSAGE (LDPL_INFO, "Incorrect view:");
618	  TV_MESSAGE (LDPL_INFO, "  Expect: " EXPECTED_VIEW);
619	  TV_MESSAGE (LDPL_INFO, "  Result: %s", result);
620	}
621      rv = tv_get_symbols_v2 (claimfile->file.handle, claimfile->n_syms_used,
622			      claimfile->symbols);
623      if (rv != LDPS_OK)
624	return rv;
625      for (n = 0; n < claimfile->n_syms_used; n++)
626	TV_MESSAGE (LDPL_INFO, "Sym: '%s%s%s' Resolution: %s",
627		    claimfile->symbols[n].name,
628		    claimfile->symbols[n].version ? "@" : "",
629		    (claimfile->symbols[n].version
630		     ? claimfile->symbols[n].version : ""),
631		    resolutions[claimfile->symbols[n].resolution]);
632      fd = claimfile->file.fd;
633      filename = xstrdup (claimfile->file.name);
634      rv = tv_release_input_file (claimfile->file.handle);
635      if (rv != LDPS_OK)
636	{
637	  free (filename);
638	  return rv;
639	}
640      if (read (fd, buffer, sizeof (buffer)) >= 0)
641	{
642	  TV_MESSAGE (LDPL_FATAL, "Unreleased file descriptor on: %s",
643		      claimfile->file.name);
644	  free (filename);
645	  return LDPS_ERR;
646	}
647      free (filename);
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.  */
668static enum ld_plugin_status
669oncleanup (void)
670{
671  TV_MESSAGE (LDPL_INFO, "hook called: cleanup.");
672  fflush (NULL);
673  return cleanup_ret;
674}
675