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