/* Standard plugin API entry point. */ enum ld_plugin_status onload (struct ld_plugin_tv *tv) { size_t n = 0; enum ld_plugin_status rv; /* This plugin does nothing but dump the tv array. It would be an error if this function was called without one. */ if (!tv) return LDPS_ERR; /* First entry should always be LDPT_MESSAGE, letting us get hold of it easily so we can send output straight away. */ if (tv[0].tv_tag == LDPT_MESSAGE) tv_message = tv[0].tv_u.tv_message; fflush (NULL); TV_MESSAGE (LDPL_INFO, "Hello from testplugin."); do if ((rv = parse_and_dump_tv_tag (n++, tv)) != LDPS_OK) return rv; while ((tv++)->tv_tag != LDPT_NULL); /* Register hooks only if instructed by options. */ if (register_claimfile_hook) { if (!tv_register_claim_file) { TV_MESSAGE (LDPL_FATAL, "No register_claim_file hook"); fflush (NULL); return LDPS_ERR; } (*tv_register_claim_file) (onclaim_file); } if (register_allsymbolsread_hook) { if (!tv_register_all_symbols_read) { TV_MESSAGE (LDPL_FATAL, "No register_all_symbols_read hook"); fflush (NULL); return LDPS_ERR; } (*tv_register_all_symbols_read) (onall_symbols_read); } if (register_cleanup_hook) { if (!tv_register_cleanup) { TV_MESSAGE (LDPL_FATAL, "No register_cleanup hook"); fflush (NULL); return LDPS_ERR; } (*tv_register_cleanup) (oncleanup); } fflush (NULL); return onload_ret; }
/* Standard plugin API registerable hook. */ static enum ld_plugin_status onall_symbols_read (void) { static const char *resolutions[] = { "LDPR_UNKNOWN", "LDPR_UNDEF", "LDPR_PREVAILING_DEF", "LDPR_PREVAILING_DEF_IRONLY", "LDPR_PREEMPTED_REG", "LDPR_PREEMPTED_IR", "LDPR_RESOLVED_IR", "LDPR_RESOLVED_EXEC", "LDPR_RESOLVED_DYN", "LDPR_PREVAILING_DEF_IRONLY_EXP", }; claim_file_t *claimfile = dumpresolutions ? claimfiles_list : NULL; add_file_t *addfile = addfiles_list; TV_MESSAGE (LDPL_INFO, "hook called: all symbols read."); for ( ; claimfile; claimfile = claimfile->next) { enum ld_plugin_status rv; int n; if (claimfile->n_syms_used && !tv_get_symbols_v2) return LDPS_ERR; else if (!claimfile->n_syms_used) continue; else if (!claimfile->file.handle) continue; rv = tv_get_symbols_v2 (claimfile->file.handle, claimfile->n_syms_used, claimfile->symbols); if (rv != LDPS_OK) return rv; for (n = 0; n < claimfile->n_syms_used; n++) TV_MESSAGE (LDPL_INFO, "Sym: '%s%s%s' Resolution: %s", claimfile->symbols[n].name, claimfile->symbols[n].version ? "@" : "", (claimfile->symbols[n].version ? claimfile->symbols[n].version : ""), resolutions[claimfile->symbols[n].resolution]); } for ( ; addfile ; addfile = addfile->next) { enum ld_plugin_status rv; if (addfile->type == ADD_LIB && tv_add_input_library) rv = (*tv_add_input_library) (addfile->name); else if (addfile->type == ADD_FILE && tv_add_input_file) rv = (*tv_add_input_file) (addfile->name); else if (addfile->type == ADD_DIR && tv_set_extra_library_path) rv = (*tv_set_extra_library_path) (addfile->name); else rv = LDPS_ERR; if (rv != LDPS_OK) return rv; } fflush (NULL); return all_symbols_read_ret; }
/* Standard plugin API registerable hook. */ static enum ld_plugin_status oncleanup (void) { TV_MESSAGE (LDPL_INFO, "hook called: cleanup."); fflush (NULL); return cleanup_ret; }
/* Standard plugin API registerable hook. */ static enum ld_plugin_status onclaim_file (const struct ld_plugin_input_file *file, int *claimed) { /* Let's see if we want to claim this file. */ claim_file_t *claimfile = claimfiles_list; while (claimfile) { if (!strcmp (file->name, claimfile->file.name)) break; claimfile = claimfile->next; } /* Inform the user/testsuite. */ TV_MESSAGE (LDPL_INFO, "hook called: claim_file %s [@%ld/%ld] %s", file->name, (long)file->offset, (long)file->filesize, claimfile ? "CLAIMED" : "not claimed"); fflush (NULL); /* If we decided to claim it, record that fact, and add any symbols that were defined for it by plugin options. */ *claimed = (claimfile != 0); if (claimfile) { claimfile->claimed = TRUE; claimfile->file = *file; if (claimfile->n_syms_used && !tv_add_symbols) return LDPS_ERR; else if (claimfile->n_syms_used) return (*tv_add_symbols) (claimfile->file.handle, claimfile->n_syms_used, claimfile->symbols); } return claim_file_ret; }
/* Output contents of transfer vector array entry in human-readable form. */ static void dump_tv_tag (size_t n, struct ld_plugin_tv *tv) { size_t tag; char unknownbuf[40]; const char *name; for (tag = 0; tag < ARRAY_SIZE (tag_names); tag++) if (tag_names[tag].tag == tv->tv_tag) break; sprintf (unknownbuf, "unknown tag #%d", tv->tv_tag); name = (tag < ARRAY_SIZE (tag_names)) ? tag_names[tag].name : unknownbuf; switch (tv->tv_tag) { case LDPT_OPTION: case LDPT_OUTPUT_NAME: TV_MESSAGE (LDPL_INFO, "tv[%d]: %s '%s'", n, name, tv->tv_u.tv_string); break; case LDPT_REGISTER_CLAIM_FILE_HOOK: case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK: case LDPT_REGISTER_CLEANUP_HOOK: case LDPT_ADD_SYMBOLS: case LDPT_GET_SYMBOLS: case LDPT_GET_SYMBOLS_V2: case LDPT_ADD_INPUT_FILE: case LDPT_MESSAGE: case LDPT_GET_INPUT_FILE: case LDPT_GET_VIEW: case LDPT_RELEASE_INPUT_FILE: case LDPT_ADD_INPUT_LIBRARY: case LDPT_SET_EXTRA_LIBRARY_PATH: TV_MESSAGE (LDPL_INFO, "tv[%d]: %s func@0x%p", n, name, (void *)(tv->tv_u.tv_message)); break; case LDPT_NULL: case LDPT_API_VERSION: case LDPT_GOLD_VERSION: case LDPT_LINKER_OUTPUT: case LDPT_GNU_LD_VERSION: default: TV_MESSAGE (LDPL_INFO, "tv[%d]: %s value %W (%d)", n, name, (bfd_vma)tv->tv_u.tv_val, tv->tv_u.tv_val); break; } }
/* Determine type of plugin option and pass to individual parsers. */ static enum ld_plugin_status parse_option (const char *opt) { if (!strncmp ("fatal", opt, 5)) { TV_MESSAGE (LDPL_FATAL, "Fatal error"); fflush (NULL); } else if (!strncmp ("error", opt, 5)) { TV_MESSAGE (LDPL_ERROR, "Error"); fflush (NULL); } else if (!strncmp ("warning", opt, 7)) { TV_MESSAGE (LDPL_WARNING, "Warning"); fflush (NULL); } else if (!strncmp ("fail", opt, 4)) return set_ret_val (opt + 4, LDPS_ERR); else if (!strncmp ("pass", opt, 4)) return set_ret_val (opt + 4, LDPS_OK); else if (!strncmp ("register", opt, 8)) return set_register_hook (opt + 8, TRUE); else if (!strncmp ("noregister", opt, 10)) return set_register_hook (opt + 10, FALSE); else if (!strncmp ("claim:", opt, 6)) return record_claim_file (opt + 6, 0); else if (!strncmp ("sym:", opt, 4)) return record_claimed_file_symbol (opt + 4); else if (!strncmp ("add:", opt, 4)) return record_add_file (opt + 4, ADD_FILE); else if (!strncmp ("lib:", opt, 4)) return record_add_file (opt + 4, ADD_LIB); else if (!strncmp ("dir:", opt, 4)) return record_add_file (opt + 4, ADD_DIR); else if (!strcmp ("dumpresolutions", opt)) dumpresolutions = TRUE; else return LDPS_ERR; return LDPS_OK; }
/* Standard plugin API registerable hook. */ static enum ld_plugin_status onclaim_file (const struct ld_plugin_input_file *file, int *claimed) { /* Possible read of some bytes out of the input file into a buffer. This simulates a plugin that reads some file content in order to decide if the file should be claimed or not. */ if (bytes_to_read_before_claim > 0) { char *buffer = malloc (bytes_to_read_before_claim); if (buffer == NULL) return LDPS_ERR; if (read (file->fd, buffer, bytes_to_read_before_claim) < 0) return LDPS_ERR; free (buffer); } /* Let's see if we want to claim this file. */ claim_file_t *claimfile = claimfiles_list; while (claimfile) { if (!strcmp (file->name, claimfile->file.name)) break; claimfile = claimfile->next; } /* Inform the user/testsuite. */ TV_MESSAGE (LDPL_INFO, "hook called: claim_file %s [@%ld/%ld] %s", file->name, (long)file->offset, (long)file->filesize, claimfile ? "CLAIMED" : "not claimed"); fflush (NULL); /* If we decided to claim it, record that fact, and add any symbols that were defined for it by plugin options. */ *claimed = (claimfile != 0); if (claimfile) { claimfile->claimed = TRUE; claimfile->file = *file; if (claimfile->n_syms_used && !tv_add_symbols) return LDPS_ERR; else if (claimfile->n_syms_used) return (*tv_add_symbols) (claimfile->file.handle, claimfile->n_syms_used, claimfile->symbols); } return claim_file_ret; }
/* Standard plugin API registerable hook. */ static enum ld_plugin_status onclaim_file (const struct ld_plugin_input_file *file, int *claimed) { /* Let's see if we want to claim this file. */ claim_file_t *claimfile = claimfiles_list; size_t len = strlen (file->name); char *name = xstrdup (file->name); char *p = name + len; bfd_boolean islib; /* Only match the file name without the directory part. */ islib = *p == 'a' && *(p - 1) == '.'; for (; p != name; p--) if (IS_DIR_SEPARATOR (*p)) { p++; break; } while (claimfile) { /* Claim the file only if the file name and size match and don't match the whole library. */ if (!strcmp (p, claimfile->file.name) && claimfile->file.filesize == file->filesize && (!islib || file->offset != 0)) break; claimfile = claimfile->next; } free (name); /* If we decided to claim it, record that fact, and add any symbols that were defined for it by plugin options. */ *claimed = (claimfile != 0); if (claimfile) { char buffer[30]; int fd; TV_MESSAGE (LDPL_INFO, "Claimed: %s [@%ld/%ld]", file->name, (long)file->offset, (long)file->filesize); claimfile->claimed = TRUE; claimfile->file = *file; if (claimfile->n_syms_used && !tv_add_symbols) claim_file_ret = LDPS_ERR; else if (claimfile->n_syms_used) claim_file_ret = (*tv_add_symbols) (claimfile->file.handle, claimfile->n_syms_used, claimfile->symbols); fd = claimfile->file.fd; name = xstrdup (claimfile->file.name); claim_file_ret = tv_release_input_file (claimfile->file.handle); if (claim_file_ret != LDPS_OK) { free (name); return claim_file_ret; } if (read (fd, buffer, sizeof (buffer)) >= 0) { claim_file_ret = LDPS_ERR; TV_MESSAGE (LDPL_FATAL, "Unreleased file descriptor on: %s", name); } free (name); } return claim_file_ret; }
/* Standard plugin API entry point. */ enum ld_plugin_status onload (struct ld_plugin_tv *tv) { enum ld_plugin_status rv; /* This plugin does nothing but dump the tv array. It would be an error if this function was called without one. */ if (!tv) return LDPS_ERR; /* First entry should always be LDPT_MESSAGE, letting us get hold of it easily so we can send output straight away. */ if (tv[0].tv_tag == LDPT_MESSAGE) tv_message = tv[0].tv_u.tv_message; do if ((rv = parse_tv_tag (tv)) != LDPS_OK) return rv; while ((tv++)->tv_tag != LDPT_NULL); /* Register hooks only if instructed by options. */ if (register_claimfile_hook) { if (!tv_register_claim_file) { TV_MESSAGE (LDPL_FATAL, "No register_claim_file hook"); fflush (NULL); return LDPS_ERR; } (*tv_register_claim_file) (onclaim_file); } if (register_allsymbolsread_hook) { if (!tv_register_all_symbols_read) { TV_MESSAGE (LDPL_FATAL, "No register_all_symbols_read hook"); fflush (NULL); return LDPS_ERR; } (*tv_register_all_symbols_read) (onall_symbols_read); } if (register_cleanup_hook) { if (!tv_register_cleanup) { TV_MESSAGE (LDPL_FATAL, "No register_cleanup hook"); fflush (NULL); return LDPS_ERR; } (*tv_register_cleanup) (oncleanup); } /* Claim testsuite/ld-plugin/func.c, standalone or in a library. Its size must be SIZE_OF_FUNC_C bytes. */ #define SIZE_OF_FUNC_C 248 if (onload_ret == LDPS_OK && (record_claim_file ("func.c", SIZE_OF_FUNC_C) != LDPS_OK || record_claimed_file_symbol ("func::0:0:0") != LDPS_OK || record_claimed_file_symbol ("_func::0:0:0") != LDPS_OK || record_claim_file ("libfunc.a", SIZE_OF_FUNC_C) != LDPS_OK || record_claimed_file_symbol ("func::0:0:0") != LDPS_OK || record_claimed_file_symbol ("_func::0:0:0") != LDPS_OK)) onload_ret = LDPS_ERR; return onload_ret; }
/* Standard plugin API registerable hook. */ static enum ld_plugin_status onall_symbols_read (void) { static const char *resolutions[] = { "LDPR_UNKNOWN", "LDPR_UNDEF", "LDPR_PREVAILING_DEF", "LDPR_PREVAILING_DEF_IRONLY", "LDPR_PREEMPTED_REG", "LDPR_PREEMPTED_IR", "LDPR_RESOLVED_IR", "LDPR_RESOLVED_EXEC", "LDPR_RESOLVED_DYN", "LDPR_PREVAILING_DEF_IRONLY_EXP", }; claim_file_t *claimfile = dumpresolutions ? claimfiles_list : NULL; add_file_t *addfile = addfiles_list; struct ld_plugin_input_file file; const void *view; char buffer[30]; int fd; char *filename; if (! allsymbolsread_silent) TV_MESSAGE (LDPL_INFO, "hook called: all symbols read."); for ( ; claimfile; claimfile = claimfile->next) { enum ld_plugin_status rv; int n; if (claimfile->n_syms_used && !tv_get_symbols_v2) return LDPS_ERR; else if (!claimfile->n_syms_used) continue; else if (!claimfile->file.handle) continue; rv = tv_get_input_file (claimfile->file.handle, &file); if (rv != LDPS_OK) return rv; TV_MESSAGE (LDPL_INFO, "Input: %s (%s)", file.name, claimfile->file.name); rv = tv_get_view (claimfile->file.handle, &view); if (rv != LDPS_OK) return rv; #define EXPECTED_VIEW "/* The first line of this file must match the expectation of" #define EXPECTED_VIEW_LENGTH (sizeof (EXPECTED_VIEW) - 1) if (file.filesize != SIZE_OF_FUNC_C || SIZE_OF_FUNC_C < EXPECTED_VIEW_LENGTH || memcmp (view, EXPECTED_VIEW, EXPECTED_VIEW_LENGTH) != 0) { char result[EXPECTED_VIEW_LENGTH + 1]; memcpy (result, view, sizeof (result)); result[EXPECTED_VIEW_LENGTH] = '\0'; TV_MESSAGE (LDPL_INFO, "Incorrect view:"); TV_MESSAGE (LDPL_INFO, " Expect: " EXPECTED_VIEW); TV_MESSAGE (LDPL_INFO, " Result: %s", result); } rv = tv_get_symbols_v2 (claimfile->file.handle, claimfile->n_syms_used, claimfile->symbols); if (rv != LDPS_OK) return rv; for (n = 0; n < claimfile->n_syms_used; n++) TV_MESSAGE (LDPL_INFO, "Sym: '%s%s%s' Resolution: %s", claimfile->symbols[n].name, claimfile->symbols[n].version ? "@" : "", (claimfile->symbols[n].version ? claimfile->symbols[n].version : ""), resolutions[claimfile->symbols[n].resolution]); fd = claimfile->file.fd; filename = xstrdup (claimfile->file.name); rv = tv_release_input_file (claimfile->file.handle); if (rv != LDPS_OK) { free (filename); return rv; } if (read (fd, buffer, sizeof (buffer)) >= 0) { TV_MESSAGE (LDPL_FATAL, "Unreleased file descriptor on: %s", claimfile->file.name); free (filename); return LDPS_ERR; } free (filename); } for ( ; addfile ; addfile = addfile->next) { enum ld_plugin_status rv; if (addfile->type == ADD_LIB && tv_add_input_library) rv = (*tv_add_input_library) (addfile->name); else if (addfile->type == ADD_FILE && tv_add_input_file) rv = (*tv_add_input_file) (addfile->name); else if (addfile->type == ADD_DIR && tv_set_extra_library_path) rv = (*tv_set_extra_library_path) (addfile->name); else rv = LDPS_ERR; if (rv != LDPS_OK) return rv; } fflush (NULL); return all_symbols_read_ret; }