160777Sobrien/* Test plugin for the GNU linker. 260777Sobrien Copyright (C) 2010-2024 Free Software Foundation, Inc. 360777Sobrien 489879Sobrien This file is part of the GNU Binutils. 560777Sobrien 677324Sobrien This program is free software; you can redistribute it and/or modify 777324Sobrien it under the terms of the GNU General Public License as published by 877324Sobrien the Free Software Foundation; either version 3 of the License, or 977324Sobrien (at your option) any later version. 1077324Sobrien 1177324Sobrien This program is distributed in the hope that it will be useful, 1260777Sobrien but WITHOUT ANY WARRANTY; without even the implied warranty of 1360777Sobrien MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1460777Sobrien GNU General Public License for more details. 1560777Sobrien 1660777Sobrien You should have received a copy of the GNU General Public License 1760777Sobrien along with this program; if not, write to the Free Software 1877324Sobrien Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 1977324Sobrien MA 02110-1301, USA. */ 2077324Sobrien 2160777Sobrien#include "sysdep.h" 2260777Sobrien#include "bfd.h" 2360777Sobrien#if BFD_SUPPORTS_PLUGINS 2460777Sobrien#include "plugin-api.h" 2560777Sobrien/* For ARRAY_SIZE macro only - we don't link the library itself. */ 2660777Sobrien#include "libiberty.h" 2760777Sobrien 2860777Sobrien#include <ctype.h> /* For isdigit. */ 2960777Sobrien 3077324Sobrienextern enum ld_plugin_status onload (struct ld_plugin_tv *tv); 3177324Sobrienstatic enum ld_plugin_status onclaim_file (const struct ld_plugin_input_file *file, 3277324Sobrien int *claimed); 3360777Sobrienstatic enum ld_plugin_status onall_symbols_read (void); 3460777Sobrienstatic enum ld_plugin_status oncleanup (void); 3560777Sobrien 3689879Sobrien/* Helper for calling plugin api message function. */ 3789879Sobrien#define TV_MESSAGE if (tv_message) (*tv_message) 3889879Sobrien 3960777Sobrien/* Struct for recording files to claim / files claimed. */ 4060777Sobrientypedef struct claim_file 4160777Sobrien{ 4260777Sobrien struct claim_file *next; 4360777Sobrien struct ld_plugin_input_file file; 4460777Sobrien bool claimed; 4560777Sobrien struct ld_plugin_symbol *symbols; 4677324Sobrien int n_syms_allocated; 4760777Sobrien int n_syms_used; 4860777Sobrien} claim_file_t; 4960777Sobrien 5060777Sobrien/* Types of things that can be added at all symbols read time. */ 5160777Sobrientypedef enum addfile_enum 5260777Sobrien{ 5360777Sobrien ADD_FILE, 5477324Sobrien ADD_LIB, 5577324Sobrien ADD_DIR 5677324Sobrien} addfile_enum_t; 5760777Sobrien 5860777Sobrien/* Struct for recording files to add to final link. */ 5960777Sobrientypedef struct add_file 6060777Sobrien{ 6160777Sobrien struct add_file *next; 6260777Sobrien const char *name; 6360777Sobrien addfile_enum_t type; 6460777Sobrien} add_file_t; 6560777Sobrien 6689879Sobrien/* Helper macro for defining array of transfer vector tags and names. */ 6789879Sobrien#define ADDENTRY(tag) { tag, #tag } 6889879Sobrien 6960777Sobrien/* Struct for looking up human-readable versions of tag names. */ 7060777Sobrientypedef struct tag_name 7160777Sobrien{ 7260777Sobrien enum ld_plugin_tag tag; 7360777Sobrien const char *name; 7460777Sobrien} tag_name_t; 7560777Sobrien 7660777Sobrien/* Array of all known tags and their names. */ 7760777Sobrienstatic const tag_name_t tag_names[] = 7860777Sobrien{ 7960777Sobrien ADDENTRY(LDPT_NULL), 8060777Sobrien ADDENTRY(LDPT_API_VERSION), 8160777Sobrien ADDENTRY(LDPT_GOLD_VERSION), 8260777Sobrien ADDENTRY(LDPT_LINKER_OUTPUT), 8360777Sobrien ADDENTRY(LDPT_OPTION), 8460777Sobrien ADDENTRY(LDPT_REGISTER_CLAIM_FILE_HOOK), 8560777Sobrien ADDENTRY(LDPT_REGISTER_CLAIM_FILE_HOOK_V2), 8660777Sobrien ADDENTRY(LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK), 8760777Sobrien ADDENTRY(LDPT_REGISTER_CLEANUP_HOOK), 8860777Sobrien ADDENTRY(LDPT_ADD_SYMBOLS), 8960777Sobrien ADDENTRY(LDPT_GET_SYMBOLS), 9060777Sobrien ADDENTRY(LDPT_GET_SYMBOLS_V2), 9160777Sobrien ADDENTRY(LDPT_ADD_INPUT_FILE), 9260777Sobrien ADDENTRY(LDPT_MESSAGE), 9360777Sobrien ADDENTRY(LDPT_GET_INPUT_FILE), 9460777Sobrien ADDENTRY(LDPT_GET_VIEW), 9560777Sobrien ADDENTRY(LDPT_RELEASE_INPUT_FILE), 9660777Sobrien ADDENTRY(LDPT_ADD_INPUT_LIBRARY), 9760777Sobrien ADDENTRY(LDPT_OUTPUT_NAME), 9860777Sobrien ADDENTRY(LDPT_SET_EXTRA_LIBRARY_PATH), 9960777Sobrien ADDENTRY(LDPT_GNU_LD_VERSION) 10060777Sobrien}; 10160777Sobrien 10260777Sobrien/* Function pointers to cache hooks passed at onload time. */ 10360777Sobrienstatic ld_plugin_register_claim_file tv_register_claim_file = 0; 10460777Sobrienstatic ld_plugin_register_claim_file_v2 tv_register_claim_file_v2 = 0; 10560777Sobrienstatic ld_plugin_register_all_symbols_read tv_register_all_symbols_read = 0; 10660777Sobrienstatic ld_plugin_register_cleanup tv_register_cleanup = 0; 10760777Sobrienstatic ld_plugin_add_symbols tv_add_symbols = 0; 10860777Sobrienstatic ld_plugin_get_symbols tv_get_symbols = 0; 10960777Sobrienstatic ld_plugin_get_symbols tv_get_symbols_v2 = 0; 11060777Sobrienstatic ld_plugin_add_input_file tv_add_input_file = 0; 11160777Sobrienstatic ld_plugin_message tv_message = 0; 11260777Sobrienstatic ld_plugin_get_input_file tv_get_input_file = 0; 11360777Sobrienstatic ld_plugin_get_view tv_get_view = 0; 11460777Sobrienstatic ld_plugin_release_input_file tv_release_input_file = 0; 11560777Sobrienstatic ld_plugin_add_input_library tv_add_input_library = 0; 11660777Sobrienstatic ld_plugin_set_extra_library_path tv_set_extra_library_path = 0; 11760777Sobrien 11860777Sobrien/* Other cached info from the transfer vector. */ 11960777Sobrienstatic enum ld_plugin_output_file_type linker_output; 12060777Sobrienstatic const char *output_name; 12160777Sobrien 12260777Sobrien/* Behaviour control flags set by plugin options. */ 12360777Sobrienstatic enum ld_plugin_status onload_ret = LDPS_OK; 12460777Sobrienstatic enum ld_plugin_status claim_file_ret = LDPS_OK; 12560777Sobrienstatic enum ld_plugin_status all_symbols_read_ret = LDPS_OK; 12660777Sobrienstatic enum ld_plugin_status cleanup_ret = LDPS_OK; 12760777Sobrienstatic bool register_claimfile_hook = false; 12860777Sobrienstatic bool register_allsymbolsread_hook = false; 12960777Sobrienstatic bool register_cleanup_hook = false; 13060777Sobrienstatic bool dumpresolutions = false; 13160777Sobrien 13260777Sobrien/* The master list of all claimable/claimed files. */ 13360777Sobrienstatic claim_file_t *claimfiles_list = NULL; 13460777Sobrien 13560777Sobrien/* We keep a tail pointer for easy linking on the end. */ 13660777Sobrienstatic claim_file_t **claimfiles_tail_chain_ptr = &claimfiles_list; 13760777Sobrien 13860777Sobrien/* The last claimed file added to the list, for receiving syms. */ 13960777Sobrienstatic claim_file_t *last_claimfile = NULL; 14060777Sobrien 14160777Sobrien/* The master list of all files to add to the final link. */ 14260777Sobrienstatic add_file_t *addfiles_list = NULL; 14360777Sobrien 14460777Sobrien/* We keep a tail pointer for easy linking on the end. */ 14560777Sobrienstatic add_file_t **addfiles_tail_chain_ptr = &addfiles_list; 14660777Sobrien 14760777Sobrien/* Number of bytes read in claim file before deciding if the file can be 14860777Sobrien claimed. */ 14960777Sobrienstatic int bytes_to_read_before_claim = 0; 15060777Sobrien 15160777Sobrien/* Add a new claimfile on the end of the chain. */ 15260777Sobrienstatic enum ld_plugin_status 15360777Sobrienrecord_claim_file (const char *file) 15460777Sobrien{ 15560777Sobrien claim_file_t *newfile; 15660777Sobrien 15760777Sobrien newfile = malloc (sizeof *newfile); 15860777Sobrien if (!newfile) 15960777Sobrien return LDPS_ERR; 16060777Sobrien memset (newfile, 0, sizeof *newfile); 16160777Sobrien /* Only setup for now is remembering the name to look for. */ 16260777Sobrien newfile->file.name = file; 16360777Sobrien /* Chain it on the end of the list. */ 16460777Sobrien *claimfiles_tail_chain_ptr = newfile; 16560777Sobrien claimfiles_tail_chain_ptr = &newfile->next; 16660777Sobrien /* Record it as active for receiving symbols to register. */ 16760777Sobrien last_claimfile = newfile; 16860777Sobrien return LDPS_OK; 16960777Sobrien} 17060777Sobrien 17160777Sobrien/* How many bytes to read before claiming (or not) an input file. */ 17260777Sobrienstatic enum ld_plugin_status 17360777Sobrienrecord_read_length (const char *length) 17460777Sobrien{ 17560777Sobrien const char *tmp; 17660777Sobrien 17760777Sobrien tmp = length; 17860777Sobrien while (*tmp != '\0' && isdigit (*tmp)) 17960777Sobrien ++tmp; 18060777Sobrien if (*tmp != '\0' || *length == '\0') 18160777Sobrien return LDPS_ERR; 18260777Sobrien 18360777Sobrien bytes_to_read_before_claim = atoi (length); 18460777Sobrien return LDPS_OK; 18560777Sobrien} 18660777Sobrien 18760777Sobrien/* Add a new addfile on the end of the chain. */ 18860777Sobrienstatic enum ld_plugin_status 18989879Sobrienrecord_add_file (const char *file, addfile_enum_t type) 19089879Sobrien{ 19189879Sobrien add_file_t *newfile; 19277324Sobrien 19377324Sobrien newfile = malloc (sizeof *newfile); 19477324Sobrien if (!newfile) 19577324Sobrien return LDPS_ERR; 19677324Sobrien newfile->next = NULL; 19777324Sobrien newfile->name = file; 19860777Sobrien newfile->type = type; 19960777Sobrien /* Chain it on the end of the list. */ 20060777Sobrien *addfiles_tail_chain_ptr = newfile; 20160777Sobrien addfiles_tail_chain_ptr = &newfile->next; 20260777Sobrien return LDPS_OK; 20360777Sobrien} 20460777Sobrien 20560777Sobrien/* Parse a command-line argument string into a symbol definition. 20660777Sobrien Symbol-strings follow the colon-separated format: 20760777Sobrien NAME:VERSION:def:vis:size:COMDATKEY 20860777Sobrien where the fields in capitals are strings and those in lower 20960777Sobrien case are integers. We don't allow to specify a resolution as 21077324Sobrien doing so is not meaningful when calling the add symbols hook. */ 21177324Sobrienstatic enum ld_plugin_status 21277324Sobrienparse_symdefstr (const char *str, struct ld_plugin_symbol *sym) 21360777Sobrien{ 21460777Sobrien int n; 21560777Sobrien long long size; 21660777Sobrien const char *colon1, *colon2, *colon5; 21760777Sobrien 21860777Sobrien /* Locate the colons separating the first two strings. */ 21960777Sobrien colon1 = strchr (str, ':'); 22060777Sobrien if (!colon1) 22160777Sobrien return LDPS_ERR; 22260777Sobrien colon2 = strchr (colon1+1, ':'); 22360777Sobrien if (!colon2) 22460777Sobrien return LDPS_ERR; 22577324Sobrien /* Name must not be empty (version may be). */ 22677324Sobrien if (colon1 == str) 22777324Sobrien return LDPS_ERR; 22860777Sobrien 22960777Sobrien /* The fifth colon and trailing comdat key string are optional, 23077324Sobrien but the intermediate ones must all be present. */ 23177324Sobrien colon5 = strchr (colon2+1, ':'); /* Actually only third so far. */ 23277324Sobrien if (!colon5) 23377324Sobrien return LDPS_ERR; 23489879Sobrien colon5 = strchr (colon5+1, ':'); /* Hopefully fourth now. */ 23589879Sobrien if (!colon5) 23689879Sobrien return LDPS_ERR; 23777324Sobrien colon5 = strchr (colon5+1, ':'); /* Optional fifth now. */ 23877324Sobrien 23977324Sobrien /* Finally we'll use sscanf to parse the numeric fields, then 24077324Sobrien we'll split out the strings which we need to allocate separate 24177324Sobrien storage for anyway so that we can add nul termination. */ 24277324Sobrien n = sscanf (colon2 + 1, "%hhi:%i:%lli", &sym->def, &sym->visibility, &size); 24377324Sobrien if (n != 3) 24477324Sobrien return LDPS_ERR; 24577324Sobrien 24689879Sobrien /* Parsed successfully, so allocate strings and fill out fields. */ 24789879Sobrien sym->size = size; 24889879Sobrien sym->unused = 0; 24989879Sobrien sym->section_kind = 0; 25089879Sobrien sym->symbol_type = 0; 25189879Sobrien sym->resolution = LDPR_UNKNOWN; 25289879Sobrien sym->name = malloc (colon1 - str + 1); 25389879Sobrien if (!sym->name) 25489879Sobrien return LDPS_ERR; 25589879Sobrien memcpy (sym->name, str, colon1 - str); 25689879Sobrien sym->name[colon1 - str] = '\0'; 25789879Sobrien 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. */ 280static enum ld_plugin_status 281record_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. */ 311static enum ld_plugin_status 312set_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. */ 328static enum ld_plugin_status 329set_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. */ 343static enum ld_plugin_status 344parse_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. */ 374static void 375dump_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. */ 423static enum ld_plugin_status 424parse_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. */ 492enum ld_plugin_status 493parse_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. */ 501enum ld_plugin_status 502onload (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. */ 561static enum ld_plugin_status 562onclaim_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. */ 611static enum ld_plugin_status 612onall_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. */ 669static enum ld_plugin_status 670oncleanup (void) 671{ 672 TV_MESSAGE (LDPL_INFO, "hook called: cleanup."); 673 fflush (NULL); 674 return cleanup_ret; 675} 676#endif /* BFD_SUPPORTS_PLUGINS */ 677