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