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