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