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