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