xref: /netbsd-src/external/gpl3/binutils/dist/ld/testplug.c (revision cb63e24e8d6aae7ddac1859a9015f48b1d8bd90e)
1 /* Test plugin for the GNU linker.
2    Copyright (C) 2010-2024 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 #if BFD_SUPPORTS_PLUGINS
24 #include "plugin-api.h"
25 /* For ARRAY_SIZE macro only - we don't link the library itself.  */
26 #include "libiberty.h"
27 
28 #include <ctype.h> /* For isdigit.  */
29 
30 extern enum ld_plugin_status onload (struct ld_plugin_tv *tv);
31 static enum ld_plugin_status onclaim_file (const struct ld_plugin_input_file *file,
32 				int *claimed);
33 static enum ld_plugin_status onall_symbols_read (void);
34 static enum ld_plugin_status oncleanup (void);
35 
36 /* Helper for calling plugin api message function.  */
37 #define TV_MESSAGE if (tv_message) (*tv_message)
38 
39 /* Struct for recording files to claim / files claimed.  */
40 typedef struct claim_file
41 {
42   struct claim_file *next;
43   struct ld_plugin_input_file file;
44   bool claimed;
45   struct ld_plugin_symbol *symbols;
46   int n_syms_allocated;
47   int n_syms_used;
48 } claim_file_t;
49 
50 /* Types of things that can be added at all symbols read time.  */
51 typedef enum addfile_enum
52 {
53   ADD_FILE,
54   ADD_LIB,
55   ADD_DIR
56 } addfile_enum_t;
57 
58 /* Struct for recording files to add to final link.  */
59 typedef struct add_file
60 {
61   struct add_file *next;
62   const char *name;
63   addfile_enum_t type;
64 } add_file_t;
65 
66 /* Helper macro for defining array of transfer vector tags and names.  */
67 #define ADDENTRY(tag) { tag, #tag }
68 
69 /* Struct for looking up human-readable versions of tag names.  */
70 typedef struct tag_name
71 {
72   enum ld_plugin_tag tag;
73   const char *name;
74 } tag_name_t;
75 
76 /* Array of all known tags and their names.  */
77 static const tag_name_t tag_names[] =
78 {
79   ADDENTRY(LDPT_NULL),
80   ADDENTRY(LDPT_API_VERSION),
81   ADDENTRY(LDPT_GOLD_VERSION),
82   ADDENTRY(LDPT_LINKER_OUTPUT),
83   ADDENTRY(LDPT_OPTION),
84   ADDENTRY(LDPT_REGISTER_CLAIM_FILE_HOOK),
85   ADDENTRY(LDPT_REGISTER_CLAIM_FILE_HOOK_V2),
86   ADDENTRY(LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK),
87   ADDENTRY(LDPT_REGISTER_CLEANUP_HOOK),
88   ADDENTRY(LDPT_ADD_SYMBOLS),
89   ADDENTRY(LDPT_GET_SYMBOLS),
90   ADDENTRY(LDPT_GET_SYMBOLS_V2),
91   ADDENTRY(LDPT_ADD_INPUT_FILE),
92   ADDENTRY(LDPT_MESSAGE),
93   ADDENTRY(LDPT_GET_INPUT_FILE),
94   ADDENTRY(LDPT_GET_VIEW),
95   ADDENTRY(LDPT_RELEASE_INPUT_FILE),
96   ADDENTRY(LDPT_ADD_INPUT_LIBRARY),
97   ADDENTRY(LDPT_OUTPUT_NAME),
98   ADDENTRY(LDPT_SET_EXTRA_LIBRARY_PATH),
99   ADDENTRY(LDPT_GNU_LD_VERSION)
100 };
101 
102 /* Function pointers to cache hooks passed at onload time.  */
103 static ld_plugin_register_claim_file tv_register_claim_file = 0;
104 static ld_plugin_register_claim_file_v2 tv_register_claim_file_v2 = 0;
105 static ld_plugin_register_all_symbols_read tv_register_all_symbols_read = 0;
106 static ld_plugin_register_cleanup tv_register_cleanup = 0;
107 static ld_plugin_add_symbols tv_add_symbols = 0;
108 static ld_plugin_get_symbols tv_get_symbols = 0;
109 static ld_plugin_get_symbols tv_get_symbols_v2 = 0;
110 static ld_plugin_add_input_file tv_add_input_file = 0;
111 static ld_plugin_message tv_message = 0;
112 static ld_plugin_get_input_file tv_get_input_file = 0;
113 static ld_plugin_get_view tv_get_view = 0;
114 static ld_plugin_release_input_file tv_release_input_file = 0;
115 static ld_plugin_add_input_library tv_add_input_library = 0;
116 static ld_plugin_set_extra_library_path tv_set_extra_library_path = 0;
117 
118 /* Other cached info from the transfer vector.  */
119 static enum ld_plugin_output_file_type linker_output;
120 static const char *output_name;
121 
122 /* Behaviour control flags set by plugin options.  */
123 static enum ld_plugin_status onload_ret = LDPS_OK;
124 static enum ld_plugin_status claim_file_ret = LDPS_OK;
125 static enum ld_plugin_status all_symbols_read_ret = LDPS_OK;
126 static enum ld_plugin_status cleanup_ret = LDPS_OK;
127 static bool register_claimfile_hook = false;
128 static bool register_allsymbolsread_hook = false;
129 static bool register_cleanup_hook = false;
130 static bool dumpresolutions = false;
131 
132 /* The master list of all claimable/claimed files.  */
133 static claim_file_t *claimfiles_list = NULL;
134 
135 /* We keep a tail pointer for easy linking on the end.  */
136 static claim_file_t **claimfiles_tail_chain_ptr = &claimfiles_list;
137 
138 /* The last claimed file added to the list, for receiving syms.  */
139 static claim_file_t *last_claimfile = NULL;
140 
141 /* The master list of all files to add to the final link.  */
142 static add_file_t *addfiles_list = NULL;
143 
144 /* We keep a tail pointer for easy linking on the end.  */
145 static add_file_t **addfiles_tail_chain_ptr = &addfiles_list;
146 
147 /* Number of bytes read in claim file before deciding if the file can be
148    claimed.  */
149 static int bytes_to_read_before_claim = 0;
150 
151 /* Add a new claimfile on the end of the chain.  */
152 static enum ld_plugin_status
record_claim_file(const char * file)153 record_claim_file (const char *file)
154 {
155   claim_file_t *newfile;
156 
157   newfile = malloc (sizeof *newfile);
158   if (!newfile)
159     return LDPS_ERR;
160   memset (newfile, 0, sizeof *newfile);
161   /* Only setup for now is remembering the name to look for.  */
162   newfile->file.name = file;
163   /* Chain it on the end of the list.  */
164   *claimfiles_tail_chain_ptr = newfile;
165   claimfiles_tail_chain_ptr = &newfile->next;
166   /* Record it as active for receiving symbols to register.  */
167   last_claimfile = newfile;
168   return LDPS_OK;
169 }
170 
171 /* How many bytes to read before claiming (or not) an input file.  */
172 static enum ld_plugin_status
record_read_length(const char * length)173 record_read_length (const char *length)
174 {
175   const char *tmp;
176 
177   tmp = length;
178   while (*tmp != '\0' && isdigit (*tmp))
179     ++tmp;
180   if (*tmp != '\0' || *length == '\0')
181     return LDPS_ERR;
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
record_add_file(const char * file,addfile_enum_t type)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
parse_symdefstr(const char * str,struct ld_plugin_symbol * sym)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, "%hhi:%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->unused = 0;
249   sym->section_kind = 0;
250   sym->symbol_type = 0;
251   sym->resolution = LDPR_UNKNOWN;
252   sym->name = malloc (colon1 - str + 1);
253   if (!sym->name)
254     return LDPS_ERR;
255   memcpy (sym->name, str, colon1 - str);
256   sym->name[colon1 - str] = '\0';
257   if (colon2 > (colon1 + 1))
258     {
259       sym->version = malloc (colon2 - colon1);
260       if (!sym->version)
261 	return LDPS_ERR;
262       memcpy (sym->version, colon1 + 1, colon2 - (colon1 + 1));
263       sym->version[colon2 - (colon1 + 1)] = '\0';
264     }
265   else
266     sym->version = NULL;
267   if (colon5 && colon5[1])
268     {
269       sym->comdat_key = malloc (strlen (colon5 + 1) + 1);
270       if (!sym->comdat_key)
271 	return LDPS_ERR;
272       strcpy (sym->comdat_key, colon5 + 1);
273     }
274   else
275     sym->comdat_key = 0;
276   return LDPS_OK;
277 }
278 
279 /* Record a symbol to be added for the last-added claimfile.  */
280 static enum ld_plugin_status
record_claimed_file_symbol(const char * symdefstr)281 record_claimed_file_symbol (const char *symdefstr)
282 {
283   struct ld_plugin_symbol sym;
284 
285   /* Can't add symbols except as belonging to claimed files.  */
286   if (!last_claimfile)
287     return LDPS_ERR;
288 
289   /* If string doesn't parse correctly, give an error.  */
290   if (parse_symdefstr (symdefstr, &sym) != LDPS_OK)
291     return LDPS_ERR;
292 
293   /* Check for enough space, resize array if needed, and add it.  */
294   if (last_claimfile->n_syms_allocated == last_claimfile->n_syms_used)
295     {
296       int new_n_syms = last_claimfile->n_syms_allocated
297 			? 2 * last_claimfile->n_syms_allocated
298 			: 10;
299       last_claimfile->symbols = realloc (last_claimfile->symbols,
300 			new_n_syms * sizeof *last_claimfile->symbols);
301       if (!last_claimfile->symbols)
302 	return LDPS_ERR;
303       last_claimfile->n_syms_allocated = new_n_syms;
304     }
305   last_claimfile->symbols[last_claimfile->n_syms_used++] = sym;
306 
307   return LDPS_OK;
308 }
309 
310 /* Records the status to return from one of the registered hooks.  */
311 static enum ld_plugin_status
set_ret_val(const char * whichval,enum ld_plugin_status retval)312 set_ret_val (const char *whichval, enum ld_plugin_status retval)
313 {
314   if (!strcmp ("onload", whichval))
315     onload_ret = retval;
316   else if (!strcmp ("claimfile", whichval))
317     claim_file_ret = retval;
318   else if (!strcmp ("allsymbolsread", whichval))
319     all_symbols_read_ret = retval;
320   else if (!strcmp ("cleanup", whichval))
321     cleanup_ret = retval;
322   else
323     return LDPS_ERR;
324   return LDPS_OK;
325 }
326 
327 /* Records hooks which should be registered.  */
328 static enum ld_plugin_status
set_register_hook(const char * whichhook,bool yesno)329 set_register_hook (const char *whichhook, bool yesno)
330 {
331   if (!strcmp ("claimfile", whichhook))
332     register_claimfile_hook = yesno;
333   else if (!strcmp ("allsymbolsread", whichhook))
334     register_allsymbolsread_hook = yesno;
335   else if (!strcmp ("cleanup", whichhook))
336     register_cleanup_hook = yesno;
337   else
338     return LDPS_ERR;
339   return LDPS_OK;
340 }
341 
342 /* Determine type of plugin option and pass to individual parsers.  */
343 static enum ld_plugin_status
parse_option(const char * opt)344 parse_option (const char *opt)
345 {
346   if (!strncmp ("fail", opt, 4))
347     return set_ret_val (opt + 4, LDPS_ERR);
348   else if (!strncmp ("pass", opt, 4))
349     return set_ret_val (opt + 4, LDPS_OK);
350   else if (!strncmp ("register", opt, 8))
351     return set_register_hook (opt + 8, true);
352   else if (!strncmp ("noregister", opt, 10))
353     return set_register_hook (opt + 10, false);
354   else if (!strncmp ("claim:", opt, 6))
355     return record_claim_file (opt + 6);
356   else if (!strncmp ("read:", opt, 5))
357     return record_read_length (opt + 5);
358   else if (!strncmp ("sym:", opt, 4))
359     return record_claimed_file_symbol (opt + 4);
360   else if (!strncmp ("add:", opt, 4))
361     return record_add_file (opt + 4, ADD_FILE);
362   else if (!strncmp ("lib:", opt, 4))
363     return record_add_file (opt + 4, ADD_LIB);
364   else if (!strncmp ("dir:", opt, 4))
365     return record_add_file (opt + 4, ADD_DIR);
366   else if (!strcmp ("dumpresolutions", opt))
367     dumpresolutions = true;
368   else
369     return LDPS_ERR;
370   return LDPS_OK;
371 }
372 
373 /* Output contents of transfer vector array entry in human-readable form.  */
374 static void
dump_tv_tag(size_t n,struct ld_plugin_tv * tv)375 dump_tv_tag (size_t n, struct ld_plugin_tv *tv)
376 {
377   size_t tag;
378   char unknownbuf[40];
379   const char *name;
380 
381   for (tag = 0; tag < ARRAY_SIZE (tag_names); tag++)
382     if (tag_names[tag].tag == tv->tv_tag)
383       break;
384   sprintf (unknownbuf, "unknown tag #%d", tv->tv_tag);
385   name = (tag < ARRAY_SIZE (tag_names)) ? tag_names[tag].name : unknownbuf;
386   switch (tv->tv_tag)
387     {
388       case LDPT_OPTION:
389       case LDPT_OUTPUT_NAME:
390 	TV_MESSAGE (LDPL_INFO, "tv[%d]: %s '%s'", n, name,
391 		    tv->tv_u.tv_string);
392         break;
393       case LDPT_REGISTER_CLAIM_FILE_HOOK:
394       case LDPT_REGISTER_CLAIM_FILE_HOOK_V2:
395       case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK:
396       case LDPT_REGISTER_CLEANUP_HOOK:
397       case LDPT_ADD_SYMBOLS:
398       case LDPT_GET_SYMBOLS:
399       case LDPT_GET_SYMBOLS_V2:
400       case LDPT_ADD_INPUT_FILE:
401       case LDPT_MESSAGE:
402       case LDPT_GET_INPUT_FILE:
403       case LDPT_GET_VIEW:
404       case LDPT_RELEASE_INPUT_FILE:
405       case LDPT_ADD_INPUT_LIBRARY:
406       case LDPT_SET_EXTRA_LIBRARY_PATH:
407 	TV_MESSAGE (LDPL_INFO, "tv[%d]: %s func@0x%p", n, name,
408 		    (void *)(tv->tv_u.tv_message));
409         break;
410       case LDPT_NULL:
411       case LDPT_API_VERSION:
412       case LDPT_GOLD_VERSION:
413       case LDPT_LINKER_OUTPUT:
414       case LDPT_GNU_LD_VERSION:
415       default:
416 	TV_MESSAGE (LDPL_INFO, "tv[%d]: %s value %W (%d)", n, name,
417 		    (bfd_vma)tv->tv_u.tv_val, tv->tv_u.tv_val);
418 	break;
419     }
420 }
421 
422 /* Handle/record information received in a transfer vector entry.  */
423 static enum ld_plugin_status
parse_tv_tag(struct ld_plugin_tv * tv)424 parse_tv_tag (struct ld_plugin_tv *tv)
425 {
426 #define SETVAR(x) x = tv->tv_u.x
427   switch (tv->tv_tag)
428     {
429       case LDPT_OPTION:
430 	return parse_option (tv->tv_u.tv_string);
431       case LDPT_NULL:
432       case LDPT_GOLD_VERSION:
433       case LDPT_GNU_LD_VERSION:
434       case LDPT_API_VERSION:
435       default:
436 	break;
437       case LDPT_OUTPUT_NAME:
438 	output_name = tv->tv_u.tv_string;
439 	break;
440       case LDPT_LINKER_OUTPUT:
441 	linker_output = tv->tv_u.tv_val;
442 	break;
443       case LDPT_REGISTER_CLAIM_FILE_HOOK:
444 	SETVAR(tv_register_claim_file);
445 	break;
446       case LDPT_REGISTER_CLAIM_FILE_HOOK_V2:
447 	SETVAR(tv_register_claim_file_v2);
448 	break;
449       case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK:
450 	SETVAR(tv_register_all_symbols_read);
451 	break;
452       case LDPT_REGISTER_CLEANUP_HOOK:
453 	SETVAR(tv_register_cleanup);
454 	break;
455       case LDPT_ADD_SYMBOLS:
456 	SETVAR(tv_add_symbols);
457 	break;
458       case LDPT_GET_SYMBOLS:
459 	SETVAR(tv_get_symbols);
460 	break;
461       case LDPT_GET_SYMBOLS_V2:
462 	tv_get_symbols_v2 = tv->tv_u.tv_get_symbols;
463 	break;
464       case LDPT_ADD_INPUT_FILE:
465 	SETVAR(tv_add_input_file);
466 	break;
467       case LDPT_MESSAGE:
468 	SETVAR(tv_message);
469 	break;
470       case LDPT_GET_INPUT_FILE:
471 	SETVAR(tv_get_input_file);
472 	break;
473       case LDPT_GET_VIEW:
474 	SETVAR(tv_get_view);
475 	break;
476       case LDPT_RELEASE_INPUT_FILE:
477 	SETVAR(tv_release_input_file);
478 	break;
479       case LDPT_ADD_INPUT_LIBRARY:
480 	SETVAR(tv_add_input_library);
481 	break;
482       case LDPT_SET_EXTRA_LIBRARY_PATH:
483 	SETVAR(tv_set_extra_library_path);
484 	break;
485     }
486 #undef SETVAR
487   return LDPS_OK;
488 }
489 
490 /* Record any useful information in transfer vector entry and display
491    it in human-readable form using the plugin API message() callback.  */
492 enum ld_plugin_status
parse_and_dump_tv_tag(size_t n,struct ld_plugin_tv * tv)493 parse_and_dump_tv_tag (size_t n, struct ld_plugin_tv *tv)
494 {
495   enum ld_plugin_status rv = parse_tv_tag (tv);
496   dump_tv_tag (n, tv);
497   return rv;
498 }
499 
500 /* Standard plugin API entry point.  */
501 enum ld_plugin_status
onload(struct ld_plugin_tv * tv)502 onload (struct ld_plugin_tv *tv)
503 {
504   size_t n = 0;
505   enum ld_plugin_status rv;
506 
507   /* This plugin does nothing but dump the tv array.  It would
508      be an error if this function was called without one.  */
509   if (!tv)
510     return LDPS_ERR;
511 
512   /* First entry should always be LDPT_MESSAGE, letting us get
513      hold of it easily so we can send output straight away.  */
514   if (tv[0].tv_tag == LDPT_MESSAGE)
515     tv_message = tv[0].tv_u.tv_message;
516 
517   fflush (NULL);
518   TV_MESSAGE (LDPL_INFO, "Hello from testplugin.");
519 
520   do
521     if ((rv = parse_and_dump_tv_tag (n++, tv)) != LDPS_OK)
522       return rv;
523   while ((tv++)->tv_tag != LDPT_NULL);
524 
525   /* Register hooks only if instructed by options.  */
526   if (register_claimfile_hook)
527     {
528       if (!tv_register_claim_file)
529 	{
530 	  TV_MESSAGE (LDPL_FATAL, "No register_claim_file hook");
531 	  fflush (NULL);
532 	  return LDPS_ERR;
533 	}
534       (*tv_register_claim_file) (onclaim_file);
535     }
536   if (register_allsymbolsread_hook)
537     {
538       if (!tv_register_all_symbols_read)
539 	{
540 	  TV_MESSAGE (LDPL_FATAL, "No register_all_symbols_read hook");
541 	  fflush (NULL);
542 	  return LDPS_ERR;
543 	}
544       (*tv_register_all_symbols_read) (onall_symbols_read);
545     }
546   if (register_cleanup_hook)
547     {
548       if (!tv_register_cleanup)
549 	{
550 	  TV_MESSAGE (LDPL_FATAL, "No register_cleanup hook");
551 	  fflush (NULL);
552 	  return LDPS_ERR;
553 	}
554       (*tv_register_cleanup) (oncleanup);
555     }
556   fflush (NULL);
557   return onload_ret;
558 }
559 
560 /* Standard plugin API registerable hook.  */
561 static enum ld_plugin_status
onclaim_file(const struct ld_plugin_input_file * file,int * claimed)562 onclaim_file (const struct ld_plugin_input_file *file, int *claimed)
563 {
564   /* Possible read of some bytes out of the input file into a buffer.  This
565      simulates a plugin that reads some file content in order to decide if
566      the file should be claimed or not.  */
567   if (bytes_to_read_before_claim > 0)
568     {
569       char *buffer = malloc (bytes_to_read_before_claim);
570 
571       if (buffer == NULL)
572         return LDPS_ERR;
573       if (read (file->fd, buffer, bytes_to_read_before_claim) < 0)
574         return LDPS_ERR;
575       free (buffer);
576     }
577 
578   /* Let's see if we want to claim this file.  */
579   claim_file_t *claimfile = claimfiles_list;
580   while (claimfile)
581     {
582       if (!strcmp (file->name, claimfile->file.name))
583 	break;
584       claimfile = claimfile->next;
585     }
586 
587   /* Inform the user/testsuite.  */
588   TV_MESSAGE (LDPL_INFO, "hook called: claim_file %s [@%ld/%ld] %s",
589 	      file->name, (long)file->offset, (long)file->filesize,
590 	      claimfile ? "CLAIMED" : "not claimed");
591   fflush (NULL);
592 
593   /* If we decided to claim it, record that fact, and add any symbols
594      that were defined for it by plugin options.  */
595   *claimed = (claimfile != 0);
596   if (claimfile)
597     {
598       claimfile->claimed = true;
599       claimfile->file = *file;
600       if (claimfile->n_syms_used && !tv_add_symbols)
601 	return LDPS_ERR;
602       else if (claimfile->n_syms_used)
603 	return (*tv_add_symbols) (claimfile->file.handle,
604 				claimfile->n_syms_used, claimfile->symbols);
605     }
606 
607   return claim_file_ret;
608 }
609 
610 /* Standard plugin API registerable hook.  */
611 static enum ld_plugin_status
onall_symbols_read(void)612 onall_symbols_read (void)
613 {
614   static const char *resolutions[] =
615     {
616       "LDPR_UNKNOWN",
617       "LDPR_UNDEF",
618       "LDPR_PREVAILING_DEF",
619       "LDPR_PREVAILING_DEF_IRONLY",
620       "LDPR_PREEMPTED_REG",
621       "LDPR_PREEMPTED_IR",
622       "LDPR_RESOLVED_IR",
623       "LDPR_RESOLVED_EXEC",
624       "LDPR_RESOLVED_DYN",
625       "LDPR_PREVAILING_DEF_IRONLY_EXP",
626     };
627   claim_file_t *claimfile = dumpresolutions ? claimfiles_list : NULL;
628   add_file_t *addfile = addfiles_list;
629   TV_MESSAGE (LDPL_INFO, "hook called: all symbols read.");
630   for ( ; claimfile; claimfile = claimfile->next)
631     {
632       enum ld_plugin_status rv;
633       int n;
634       if (claimfile->n_syms_used && !tv_get_symbols_v2)
635 	return LDPS_ERR;
636       else if (!claimfile->n_syms_used)
637         continue;
638       rv = tv_get_symbols_v2 (claimfile->file.handle, claimfile->n_syms_used,
639 			      claimfile->symbols);
640       if (rv != LDPS_OK)
641 	return rv;
642       for (n = 0; n < claimfile->n_syms_used; n++)
643 	TV_MESSAGE (LDPL_INFO, "Sym: '%s%s%s' Resolution: %s",
644 		    claimfile->symbols[n].name,
645 		    claimfile->symbols[n].version ? "@" : "",
646 		    (claimfile->symbols[n].version
647 		     ? claimfile->symbols[n].version : ""),
648 		    resolutions[claimfile->symbols[n].resolution]);
649     }
650   for ( ; addfile ; addfile = addfile->next)
651     {
652       enum ld_plugin_status rv;
653       if (addfile->type == ADD_LIB && tv_add_input_library)
654 	rv = (*tv_add_input_library) (addfile->name);
655       else if (addfile->type == ADD_FILE && tv_add_input_file)
656 	rv = (*tv_add_input_file) (addfile->name);
657       else if (addfile->type == ADD_DIR && tv_set_extra_library_path)
658 	rv = (*tv_set_extra_library_path) (addfile->name);
659       else
660 	rv = LDPS_ERR;
661       if (rv != LDPS_OK)
662 	return rv;
663     }
664   fflush (NULL);
665   return all_symbols_read_ret;
666 }
667 
668 /* Standard plugin API registerable hook.  */
669 static enum ld_plugin_status
oncleanup(void)670 oncleanup (void)
671 {
672   TV_MESSAGE (LDPL_INFO, "hook called: cleanup.");
673   fflush (NULL);
674   return cleanup_ret;
675 }
676 #endif /* BFD_SUPPORTS_PLUGINS */
677