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