1 /* Test plugin for the GNU linker.
2    Copyright (C) 2010-2021 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_ALL_SYMBOLS_READ_HOOK),
86   ADDENTRY(LDPT_REGISTER_CLEANUP_HOOK),
87   ADDENTRY(LDPT_ADD_SYMBOLS),
88   ADDENTRY(LDPT_GET_SYMBOLS),
89   ADDENTRY(LDPT_GET_SYMBOLS_V2),
90   ADDENTRY(LDPT_ADD_INPUT_FILE),
91   ADDENTRY(LDPT_MESSAGE),
92   ADDENTRY(LDPT_GET_INPUT_FILE),
93   ADDENTRY(LDPT_GET_VIEW),
94   ADDENTRY(LDPT_RELEASE_INPUT_FILE),
95   ADDENTRY(LDPT_ADD_INPUT_LIBRARY),
96   ADDENTRY(LDPT_OUTPUT_NAME),
97   ADDENTRY(LDPT_SET_EXTRA_LIBRARY_PATH),
98   ADDENTRY(LDPT_GNU_LD_VERSION)
99 };
100 
101 /* Function pointers to cache hooks passed at onload time.  */
102 static ld_plugin_register_claim_file tv_register_claim_file = 0;
103 static ld_plugin_register_all_symbols_read tv_register_all_symbols_read = 0;
104 static ld_plugin_register_cleanup tv_register_cleanup = 0;
105 static ld_plugin_add_symbols tv_add_symbols = 0;
106 static ld_plugin_get_symbols tv_get_symbols = 0;
107 static ld_plugin_get_symbols tv_get_symbols_v2 = 0;
108 static ld_plugin_add_input_file tv_add_input_file = 0;
109 static ld_plugin_message tv_message = 0;
110 static ld_plugin_get_input_file tv_get_input_file = 0;
111 static ld_plugin_get_view tv_get_view = 0;
112 static ld_plugin_release_input_file tv_release_input_file = 0;
113 static ld_plugin_add_input_library tv_add_input_library = 0;
114 static ld_plugin_set_extra_library_path tv_set_extra_library_path = 0;
115 
116 /* Other cached info from the transfer vector.  */
117 static enum ld_plugin_output_file_type linker_output;
118 static const char *output_name;
119 
120 /* Behaviour control flags set by plugin options.  */
121 static enum ld_plugin_status onload_ret = LDPS_OK;
122 static enum ld_plugin_status claim_file_ret = LDPS_OK;
123 static enum ld_plugin_status all_symbols_read_ret = LDPS_OK;
124 static enum ld_plugin_status cleanup_ret = LDPS_OK;
125 static bool register_claimfile_hook = false;
126 static bool register_allsymbolsread_hook = false;
127 static bool register_cleanup_hook = false;
128 static bool dumpresolutions = false;
129 
130 /* The master list of all claimable/claimed files.  */
131 static claim_file_t *claimfiles_list = NULL;
132 
133 /* We keep a tail pointer for easy linking on the end.  */
134 static claim_file_t **claimfiles_tail_chain_ptr = &claimfiles_list;
135 
136 /* The last claimed file added to the list, for receiving syms.  */
137 static claim_file_t *last_claimfile = NULL;
138 
139 /* The master list of all files to add to the final link.  */
140 static add_file_t *addfiles_list = NULL;
141 
142 /* We keep a tail pointer for easy linking on the end.  */
143 static add_file_t **addfiles_tail_chain_ptr = &addfiles_list;
144 
145 /* Number of bytes read in claim file before deciding if the file can be
146    claimed.  */
147 static int bytes_to_read_before_claim = 0;
148 
149 /* Add a new claimfile on the end of the chain.  */
150 static enum ld_plugin_status
record_claim_file(const char * file)151 record_claim_file (const char *file)
152 {
153   claim_file_t *newfile;
154 
155   newfile = malloc (sizeof *newfile);
156   if (!newfile)
157     return LDPS_ERR;
158   memset (newfile, 0, sizeof *newfile);
159   /* Only setup for now is remembering the name to look for.  */
160   newfile->file.name = file;
161   /* Chain it on the end of the list.  */
162   *claimfiles_tail_chain_ptr = newfile;
163   claimfiles_tail_chain_ptr = &newfile->next;
164   /* Record it as active for receiving symbols to register.  */
165   last_claimfile = newfile;
166   return LDPS_OK;
167 }
168 
169 /* How many bytes to read before claiming (or not) an input file.  */
170 static enum ld_plugin_status
record_read_length(const char * length)171 record_read_length (const char *length)
172 {
173   const char *tmp;
174 
175   tmp = length;
176   while (*tmp != '\0' && isdigit (*tmp))
177     ++tmp;
178   if (*tmp != '\0' || *length == '\0')
179     return LDPS_ERR;
180 
181   bytes_to_read_before_claim = atoi (length);
182   return LDPS_OK;
183 }
184 
185 /* Add a new addfile on the end of the chain.  */
186 static enum ld_plugin_status
record_add_file(const char * file,addfile_enum_t type)187 record_add_file (const char *file, addfile_enum_t type)
188 {
189   add_file_t *newfile;
190 
191   newfile = malloc (sizeof *newfile);
192   if (!newfile)
193     return LDPS_ERR;
194   newfile->next = NULL;
195   newfile->name = file;
196   newfile->type = type;
197   /* Chain it on the end of the list.  */
198   *addfiles_tail_chain_ptr = newfile;
199   addfiles_tail_chain_ptr = &newfile->next;
200   return LDPS_OK;
201 }
202 
203 /* Parse a command-line argument string into a symbol definition.
204    Symbol-strings follow the colon-separated format:
205 	NAME:VERSION:def:vis:size:COMDATKEY
206    where the fields in capitals are strings and those in lower
207    case are integers.  We don't allow to specify a resolution as
208    doing so is not meaningful when calling the add symbols hook.  */
209 static enum ld_plugin_status
parse_symdefstr(const char * str,struct ld_plugin_symbol * sym)210 parse_symdefstr (const char *str, struct ld_plugin_symbol *sym)
211 {
212   int n;
213   long long size;
214   const char *colon1, *colon2, *colon5;
215 
216   /* Locate the colons separating the first two strings.  */
217   colon1 = strchr (str, ':');
218   if (!colon1)
219     return LDPS_ERR;
220   colon2 = strchr (colon1+1, ':');
221   if (!colon2)
222     return LDPS_ERR;
223   /* Name must not be empty (version may be).  */
224   if (colon1 == str)
225     return LDPS_ERR;
226 
227   /* The fifth colon and trailing comdat key string are optional,
228      but the intermediate ones must all be present.  */
229   colon5 = strchr (colon2+1, ':');	/* Actually only third so far.  */
230   if (!colon5)
231     return LDPS_ERR;
232   colon5 = strchr (colon5+1, ':');	/* Hopefully fourth now.  */
233   if (!colon5)
234     return LDPS_ERR;
235   colon5 = strchr (colon5+1, ':');	/* Optional fifth now.  */
236 
237   /* Finally we'll use sscanf to parse the numeric fields, then
238      we'll split out the strings which we need to allocate separate
239      storage for anyway so that we can add nul termination.  */
240   n = sscanf (colon2 + 1, "%hhi:%i:%lli", &sym->def, &sym->visibility, &size);
241   if (n != 3)
242     return LDPS_ERR;
243 
244   /* Parsed successfully, so allocate strings and fill out fields.  */
245   sym->size = size;
246   sym->unused = 0;
247   sym->section_kind = 0;
248   sym->symbol_type = 0;
249   sym->resolution = LDPR_UNKNOWN;
250   sym->name = malloc (colon1 - str + 1);
251   if (!sym->name)
252     return LDPS_ERR;
253   memcpy (sym->name, str, colon1 - str);
254   sym->name[colon1 - str] = '\0';
255   if (colon2 > (colon1 + 1))
256     {
257       sym->version = malloc (colon2 - colon1);
258       if (!sym->version)
259 	return LDPS_ERR;
260       memcpy (sym->version, colon1 + 1, colon2 - (colon1 + 1));
261       sym->version[colon2 - (colon1 + 1)] = '\0';
262     }
263   else
264     sym->version = NULL;
265   if (colon5 && colon5[1])
266     {
267       sym->comdat_key = malloc (strlen (colon5 + 1) + 1);
268       if (!sym->comdat_key)
269 	return LDPS_ERR;
270       strcpy (sym->comdat_key, colon5 + 1);
271     }
272   else
273     sym->comdat_key = 0;
274   return LDPS_OK;
275 }
276 
277 /* Record a symbol to be added for the last-added claimfile.  */
278 static enum ld_plugin_status
record_claimed_file_symbol(const char * symdefstr)279 record_claimed_file_symbol (const char *symdefstr)
280 {
281   struct ld_plugin_symbol sym;
282 
283   /* Can't add symbols except as belonging to claimed files.  */
284   if (!last_claimfile)
285     return LDPS_ERR;
286 
287   /* If string doesn't parse correctly, give an error.  */
288   if (parse_symdefstr (symdefstr, &sym) != LDPS_OK)
289     return LDPS_ERR;
290 
291   /* Check for enough space, resize array if needed, and add it.  */
292   if (last_claimfile->n_syms_allocated == last_claimfile->n_syms_used)
293     {
294       int new_n_syms = last_claimfile->n_syms_allocated
295 			? 2 * last_claimfile->n_syms_allocated
296 			: 10;
297       last_claimfile->symbols = realloc (last_claimfile->symbols,
298 			new_n_syms * sizeof *last_claimfile->symbols);
299       if (!last_claimfile->symbols)
300 	return LDPS_ERR;
301       last_claimfile->n_syms_allocated = new_n_syms;
302     }
303   last_claimfile->symbols[last_claimfile->n_syms_used++] = sym;
304 
305   return LDPS_OK;
306 }
307 
308 /* Records the status to return from one of the registered hooks.  */
309 static enum ld_plugin_status
set_ret_val(const char * whichval,enum ld_plugin_status retval)310 set_ret_val (const char *whichval, enum ld_plugin_status retval)
311 {
312   if (!strcmp ("onload", whichval))
313     onload_ret = retval;
314   else if (!strcmp ("claimfile", whichval))
315     claim_file_ret = retval;
316   else if (!strcmp ("allsymbolsread", whichval))
317     all_symbols_read_ret = retval;
318   else if (!strcmp ("cleanup", whichval))
319     cleanup_ret = retval;
320   else
321     return LDPS_ERR;
322   return LDPS_OK;
323 }
324 
325 /* Records hooks which should be registered.  */
326 static enum ld_plugin_status
set_register_hook(const char * whichhook,bool yesno)327 set_register_hook (const char *whichhook, bool yesno)
328 {
329   if (!strcmp ("claimfile", whichhook))
330     register_claimfile_hook = yesno;
331   else if (!strcmp ("allsymbolsread", whichhook))
332     register_allsymbolsread_hook = yesno;
333   else if (!strcmp ("cleanup", whichhook))
334     register_cleanup_hook = yesno;
335   else
336     return LDPS_ERR;
337   return LDPS_OK;
338 }
339 
340 /* Determine type of plugin option and pass to individual parsers.  */
341 static enum ld_plugin_status
parse_option(const char * opt)342 parse_option (const char *opt)
343 {
344   if (!strncmp ("fail", opt, 4))
345     return set_ret_val (opt + 4, LDPS_ERR);
346   else if (!strncmp ("pass", opt, 4))
347     return set_ret_val (opt + 4, LDPS_OK);
348   else if (!strncmp ("register", opt, 8))
349     return set_register_hook (opt + 8, true);
350   else if (!strncmp ("noregister", opt, 10))
351     return set_register_hook (opt + 10, false);
352   else if (!strncmp ("claim:", opt, 6))
353     return record_claim_file (opt + 6);
354   else if (!strncmp ("read:", opt, 5))
355     return record_read_length (opt + 5);
356   else if (!strncmp ("sym:", opt, 4))
357     return record_claimed_file_symbol (opt + 4);
358   else if (!strncmp ("add:", opt, 4))
359     return record_add_file (opt + 4, ADD_FILE);
360   else if (!strncmp ("lib:", opt, 4))
361     return record_add_file (opt + 4, ADD_LIB);
362   else if (!strncmp ("dir:", opt, 4))
363     return record_add_file (opt + 4, ADD_DIR);
364   else if (!strcmp ("dumpresolutions", opt))
365     dumpresolutions = true;
366   else
367     return LDPS_ERR;
368   return LDPS_OK;
369 }
370 
371 /* Output contents of transfer vector array entry in human-readable form.  */
372 static void
dump_tv_tag(size_t n,struct ld_plugin_tv * tv)373 dump_tv_tag (size_t n, struct ld_plugin_tv *tv)
374 {
375   size_t tag;
376   char unknownbuf[40];
377   const char *name;
378 
379   for (tag = 0; tag < ARRAY_SIZE (tag_names); tag++)
380     if (tag_names[tag].tag == tv->tv_tag)
381       break;
382   sprintf (unknownbuf, "unknown tag #%d", tv->tv_tag);
383   name = (tag < ARRAY_SIZE (tag_names)) ? tag_names[tag].name : unknownbuf;
384   switch (tv->tv_tag)
385     {
386       case LDPT_OPTION:
387       case LDPT_OUTPUT_NAME:
388 	TV_MESSAGE (LDPL_INFO, "tv[%d]: %s '%s'", n, name,
389 		    tv->tv_u.tv_string);
390         break;
391       case LDPT_REGISTER_CLAIM_FILE_HOOK:
392       case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK:
393       case LDPT_REGISTER_CLEANUP_HOOK:
394       case LDPT_ADD_SYMBOLS:
395       case LDPT_GET_SYMBOLS:
396       case LDPT_GET_SYMBOLS_V2:
397       case LDPT_ADD_INPUT_FILE:
398       case LDPT_MESSAGE:
399       case LDPT_GET_INPUT_FILE:
400       case LDPT_GET_VIEW:
401       case LDPT_RELEASE_INPUT_FILE:
402       case LDPT_ADD_INPUT_LIBRARY:
403       case LDPT_SET_EXTRA_LIBRARY_PATH:
404 	TV_MESSAGE (LDPL_INFO, "tv[%d]: %s func@0x%p", n, name,
405 		    (void *)(tv->tv_u.tv_message));
406         break;
407       case LDPT_NULL:
408       case LDPT_API_VERSION:
409       case LDPT_GOLD_VERSION:
410       case LDPT_LINKER_OUTPUT:
411       case LDPT_GNU_LD_VERSION:
412       default:
413 	TV_MESSAGE (LDPL_INFO, "tv[%d]: %s value %W (%d)", n, name,
414 		    (bfd_vma)tv->tv_u.tv_val, tv->tv_u.tv_val);
415 	break;
416     }
417 }
418 
419 /* Handle/record information received in a transfer vector entry.  */
420 static enum ld_plugin_status
parse_tv_tag(struct ld_plugin_tv * tv)421 parse_tv_tag (struct ld_plugin_tv *tv)
422 {
423 #define SETVAR(x) x = tv->tv_u.x
424   switch (tv->tv_tag)
425     {
426       case LDPT_OPTION:
427 	return parse_option (tv->tv_u.tv_string);
428       case LDPT_NULL:
429       case LDPT_GOLD_VERSION:
430       case LDPT_GNU_LD_VERSION:
431       case LDPT_API_VERSION:
432       default:
433 	break;
434       case LDPT_OUTPUT_NAME:
435 	output_name = tv->tv_u.tv_string;
436 	break;
437       case LDPT_LINKER_OUTPUT:
438 	linker_output = tv->tv_u.tv_val;
439 	break;
440       case LDPT_REGISTER_CLAIM_FILE_HOOK:
441 	SETVAR(tv_register_claim_file);
442 	break;
443       case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK:
444 	SETVAR(tv_register_all_symbols_read);
445 	break;
446       case LDPT_REGISTER_CLEANUP_HOOK:
447 	SETVAR(tv_register_cleanup);
448 	break;
449       case LDPT_ADD_SYMBOLS:
450 	SETVAR(tv_add_symbols);
451 	break;
452       case LDPT_GET_SYMBOLS:
453 	SETVAR(tv_get_symbols);
454 	break;
455       case LDPT_GET_SYMBOLS_V2:
456 	tv_get_symbols_v2 = tv->tv_u.tv_get_symbols;
457 	break;
458       case LDPT_ADD_INPUT_FILE:
459 	SETVAR(tv_add_input_file);
460 	break;
461       case LDPT_MESSAGE:
462 	SETVAR(tv_message);
463 	break;
464       case LDPT_GET_INPUT_FILE:
465 	SETVAR(tv_get_input_file);
466 	break;
467       case LDPT_GET_VIEW:
468 	SETVAR(tv_get_view);
469 	break;
470       case LDPT_RELEASE_INPUT_FILE:
471 	SETVAR(tv_release_input_file);
472 	break;
473       case LDPT_ADD_INPUT_LIBRARY:
474 	SETVAR(tv_add_input_library);
475 	break;
476       case LDPT_SET_EXTRA_LIBRARY_PATH:
477 	SETVAR(tv_set_extra_library_path);
478 	break;
479     }
480 #undef SETVAR
481   return LDPS_OK;
482 }
483 
484 /* Record any useful information in transfer vector entry and display
485    it in human-readable form using the plugin API message() callback.  */
486 enum ld_plugin_status
parse_and_dump_tv_tag(size_t n,struct ld_plugin_tv * tv)487 parse_and_dump_tv_tag (size_t n, struct ld_plugin_tv *tv)
488 {
489   enum ld_plugin_status rv = parse_tv_tag (tv);
490   dump_tv_tag (n, tv);
491   return rv;
492 }
493 
494 /* Standard plugin API entry point.  */
495 enum ld_plugin_status
onload(struct ld_plugin_tv * tv)496 onload (struct ld_plugin_tv *tv)
497 {
498   size_t n = 0;
499   enum ld_plugin_status rv;
500 
501   /* This plugin does nothing but dump the tv array.  It would
502      be an error if this function was called without one.  */
503   if (!tv)
504     return LDPS_ERR;
505 
506   /* First entry should always be LDPT_MESSAGE, letting us get
507      hold of it easily so we can send output straight away.  */
508   if (tv[0].tv_tag == LDPT_MESSAGE)
509     tv_message = tv[0].tv_u.tv_message;
510 
511   fflush (NULL);
512   TV_MESSAGE (LDPL_INFO, "Hello from testplugin.");
513 
514   do
515     if ((rv = parse_and_dump_tv_tag (n++, tv)) != LDPS_OK)
516       return rv;
517   while ((tv++)->tv_tag != LDPT_NULL);
518 
519   /* Register hooks only if instructed by options.  */
520   if (register_claimfile_hook)
521     {
522       if (!tv_register_claim_file)
523 	{
524 	  TV_MESSAGE (LDPL_FATAL, "No register_claim_file hook");
525 	  fflush (NULL);
526 	  return LDPS_ERR;
527 	}
528       (*tv_register_claim_file) (onclaim_file);
529     }
530   if (register_allsymbolsread_hook)
531     {
532       if (!tv_register_all_symbols_read)
533 	{
534 	  TV_MESSAGE (LDPL_FATAL, "No register_all_symbols_read hook");
535 	  fflush (NULL);
536 	  return LDPS_ERR;
537 	}
538       (*tv_register_all_symbols_read) (onall_symbols_read);
539     }
540   if (register_cleanup_hook)
541     {
542       if (!tv_register_cleanup)
543 	{
544 	  TV_MESSAGE (LDPL_FATAL, "No register_cleanup hook");
545 	  fflush (NULL);
546 	  return LDPS_ERR;
547 	}
548       (*tv_register_cleanup) (oncleanup);
549     }
550   fflush (NULL);
551   return onload_ret;
552 }
553 
554 /* Standard plugin API registerable hook.  */
555 static enum ld_plugin_status
onclaim_file(const struct ld_plugin_input_file * file,int * claimed)556 onclaim_file (const struct ld_plugin_input_file *file, int *claimed)
557 {
558   /* Possible read of some bytes out of the input file into a buffer.  This
559      simulates a plugin that reads some file content in order to decide if
560      the file should be claimed or not.  */
561   if (bytes_to_read_before_claim > 0)
562     {
563       char *buffer = malloc (bytes_to_read_before_claim);
564 
565       if (buffer == NULL)
566         return LDPS_ERR;
567       if (read (file->fd, buffer, bytes_to_read_before_claim) < 0)
568         return LDPS_ERR;
569       free (buffer);
570     }
571 
572   /* Let's see if we want to claim this file.  */
573   claim_file_t *claimfile = claimfiles_list;
574   while (claimfile)
575     {
576       if (!strcmp (file->name, claimfile->file.name))
577 	break;
578       claimfile = claimfile->next;
579     }
580 
581   /* Inform the user/testsuite.  */
582   TV_MESSAGE (LDPL_INFO, "hook called: claim_file %s [@%ld/%ld] %s",
583 	      file->name, (long)file->offset, (long)file->filesize,
584 	      claimfile ? "CLAIMED" : "not claimed");
585   fflush (NULL);
586 
587   /* If we decided to claim it, record that fact, and add any symbols
588      that were defined for it by plugin options.  */
589   *claimed = (claimfile != 0);
590   if (claimfile)
591     {
592       claimfile->claimed = true;
593       claimfile->file = *file;
594       if (claimfile->n_syms_used && !tv_add_symbols)
595 	return LDPS_ERR;
596       else if (claimfile->n_syms_used)
597 	return (*tv_add_symbols) (claimfile->file.handle,
598 				claimfile->n_syms_used, claimfile->symbols);
599     }
600 
601   return claim_file_ret;
602 }
603 
604 /* Standard plugin API registerable hook.  */
605 static enum ld_plugin_status
onall_symbols_read(void)606 onall_symbols_read (void)
607 {
608   static const char *resolutions[] =
609     {
610       "LDPR_UNKNOWN",
611       "LDPR_UNDEF",
612       "LDPR_PREVAILING_DEF",
613       "LDPR_PREVAILING_DEF_IRONLY",
614       "LDPR_PREEMPTED_REG",
615       "LDPR_PREEMPTED_IR",
616       "LDPR_RESOLVED_IR",
617       "LDPR_RESOLVED_EXEC",
618       "LDPR_RESOLVED_DYN",
619       "LDPR_PREVAILING_DEF_IRONLY_EXP",
620     };
621   claim_file_t *claimfile = dumpresolutions ? claimfiles_list : NULL;
622   add_file_t *addfile = addfiles_list;
623   TV_MESSAGE (LDPL_INFO, "hook called: all symbols read.");
624   for ( ; claimfile; claimfile = claimfile->next)
625     {
626       enum ld_plugin_status rv;
627       int n;
628       if (claimfile->n_syms_used && !tv_get_symbols_v2)
629 	return LDPS_ERR;
630       else if (!claimfile->n_syms_used)
631         continue;
632       rv = tv_get_symbols_v2 (claimfile->file.handle, claimfile->n_syms_used,
633 			      claimfile->symbols);
634       if (rv != LDPS_OK)
635 	return rv;
636       for (n = 0; n < claimfile->n_syms_used; n++)
637 	TV_MESSAGE (LDPL_INFO, "Sym: '%s%s%s' Resolution: %s",
638 		    claimfile->symbols[n].name,
639 		    claimfile->symbols[n].version ? "@" : "",
640 		    (claimfile->symbols[n].version
641 		     ? claimfile->symbols[n].version : ""),
642 		    resolutions[claimfile->symbols[n].resolution]);
643     }
644   for ( ; addfile ; addfile = addfile->next)
645     {
646       enum ld_plugin_status rv;
647       if (addfile->type == ADD_LIB && tv_add_input_library)
648 	rv = (*tv_add_input_library) (addfile->name);
649       else if (addfile->type == ADD_FILE && tv_add_input_file)
650 	rv = (*tv_add_input_file) (addfile->name);
651       else if (addfile->type == ADD_DIR && tv_set_extra_library_path)
652 	rv = (*tv_set_extra_library_path) (addfile->name);
653       else
654 	rv = LDPS_ERR;
655       if (rv != LDPS_OK)
656 	return rv;
657     }
658   fflush (NULL);
659   return all_symbols_read_ret;
660 }
661 
662 /* Standard plugin API registerable hook.  */
663 static enum ld_plugin_status
oncleanup(void)664 oncleanup (void)
665 {
666   TV_MESSAGE (LDPL_INFO, "hook called: cleanup.");
667   fflush (NULL);
668   return cleanup_ret;
669 }
670 #endif /* BFD_SUPPORTS_PLUGINS */
671