(root)/
binutils-2.41/
ld/
testplug.c
       1  /* Test plugin for the GNU linker.
       2     Copyright (C) 2010-2023 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 */