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