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