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