xref: /netbsd-src/external/gpl3/binutils.old/dist/ld/testplug.c (revision d16b7486a53dcb8072b60ec6fcb4373a2d0c27b7)
1 /* Test plugin for the GNU linker.
2    Copyright (C) 2010-2020 Free Software Foundation, Inc.
3 
4    This file is part of the GNU Binutils.
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19    MA 02110-1301, USA.  */
20 
21 #include "sysdep.h"
22 #include "bfd.h"
23 #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 }
669