Provide string description of definition, visibility and resolution in LTO plug-in.
[external/binutils.git] / ld / testplug.c
1 /* Test plugin for the GNU linker.
2    Copyright (C) 2010-2019 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
29 extern enum ld_plugin_status onload (struct ld_plugin_tv *tv);
30 static enum ld_plugin_status onclaim_file (const struct ld_plugin_input_file *file,
31                                 int *claimed);
32 static enum ld_plugin_status onall_symbols_read (void);
33 static 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.  */
39 typedef 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.  */
50 typedef 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.  */
58 typedef 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.  */
69 typedef 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.  */
76 static 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.  */
101 static ld_plugin_register_claim_file tv_register_claim_file = 0;
102 static ld_plugin_register_all_symbols_read tv_register_all_symbols_read = 0;
103 static ld_plugin_register_cleanup tv_register_cleanup = 0;
104 static ld_plugin_add_symbols tv_add_symbols = 0;
105 static ld_plugin_get_symbols tv_get_symbols = 0;
106 static ld_plugin_get_symbols tv_get_symbols_v2 = 0;
107 static ld_plugin_add_input_file tv_add_input_file = 0;
108 static ld_plugin_message tv_message = 0;
109 static ld_plugin_get_input_file tv_get_input_file = 0;
110 static ld_plugin_get_view tv_get_view = 0;
111 static ld_plugin_release_input_file tv_release_input_file = 0;
112 static ld_plugin_add_input_library tv_add_input_library = 0;
113 static ld_plugin_set_extra_library_path tv_set_extra_library_path = 0;
114
115 /* Other cached info from the transfer vector.  */
116 static enum ld_plugin_output_file_type linker_output;
117 static const char *output_name;
118
119 /* Behaviour control flags set by plugin options.  */
120 static enum ld_plugin_status onload_ret = LDPS_OK;
121 static enum ld_plugin_status claim_file_ret = LDPS_OK;
122 static enum ld_plugin_status all_symbols_read_ret = LDPS_OK;
123 static enum ld_plugin_status cleanup_ret = LDPS_OK;
124 static bfd_boolean register_claimfile_hook = FALSE;
125 static bfd_boolean register_allsymbolsread_hook = FALSE;
126 static bfd_boolean register_cleanup_hook = FALSE;
127 static bfd_boolean dumpresolutions = FALSE;
128
129 /* The master list of all claimable/claimed files.  */
130 static claim_file_t *claimfiles_list = NULL;
131
132 /* We keep a tail pointer for easy linking on the end.  */
133 static claim_file_t **claimfiles_tail_chain_ptr = &claimfiles_list;
134
135 /* The last claimed file added to the list, for receiving syms.  */
136 static claim_file_t *last_claimfile = NULL;
137
138 /* The master list of all files to add to the final link.  */
139 static add_file_t *addfiles_list = NULL;
140
141 /* We keep a tail pointer for easy linking on the end.  */
142 static 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.  */
146 static int bytes_to_read_before_claim = 0;
147
148 /* Add a new claimfile on the end of the chain.  */
149 static enum ld_plugin_status
150 record_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.  */
169 static enum ld_plugin_status
170 record_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.  */
188 static enum ld_plugin_status
189 record_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.  */
211 static enum ld_plugin_status
212 parse_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.  */
277 static enum ld_plugin_status
278 record_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.  */
308 static enum ld_plugin_status
309 set_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.  */
325 static enum ld_plugin_status
326 set_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.  */
340 static enum ld_plugin_status
341 parse_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.  */
371 static void
372 dump_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.  */
419 static enum ld_plugin_status
420 parse_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.  */
485 enum ld_plugin_status
486 parse_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.  */
494 enum ld_plugin_status
495 onload (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.  */
554 static enum ld_plugin_status
555 onclaim_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.  */
604 static enum ld_plugin_status
605 onall_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.  */
662 static enum ld_plugin_status
663 oncleanup (void)
664 {
665   TV_MESSAGE (LDPL_INFO, "hook called: cleanup.");
666   fflush (NULL);
667   return cleanup_ret;
668 }