123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360 |
- /* Program to read the IL symbol table.
- Copyright (C) 2008 Free Software Foundation, Inc.
- Contributed by Rafael Avila de Espindola (espindola@google.com).
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
- #include <fcntl.h>
- #include <assert.h>
- #include <dlfcn.h>
- #include <stdio.h>
- #include <inttypes.h>
- #include <stdlib.h>
- #include <string.h>
- #include "plugin-api.h"
- #include "../gcc/lto/common.h"
- /* The presence of gelf.h is checked by the toplevel configure script. */
- # include <gelf.h>
- static ld_plugin_claim_file_handler claim_file_handler;
- static ld_plugin_all_symbols_read_handler all_symbols_read_handler;
- static ld_plugin_cleanup_handler cleanup_handler;
- static void *plugin_handle;
- struct file_handle {
- unsigned nsyms;
- struct ld_plugin_symbol *syms;
- };
- static struct file_handle **all_file_handles = NULL;
- static unsigned int num_file_handles;
- /* Write NSYMS symbols from file HANDLE in SYMS. */
- static enum ld_plugin_status
- get_symbols (const void *handle, int nsyms, struct ld_plugin_symbol *syms)
- {
- unsigned i;
- struct file_handle *h = (struct file_handle *) handle;
- assert (h->nsyms == nsyms);
- for (i = 0; i < nsyms; i++)
- syms[i] = h->syms[i];
- return LDPS_OK;
- }
- /* Register HANDLER as the callback for notifying the plugin that all symbols
- have been read. */
- static enum ld_plugin_status
- register_all_symbols_read (ld_plugin_all_symbols_read_handler handler)
- {
- all_symbols_read_handler = handler;
- return LDPS_OK;
- }
- /* Register HANDLER as the callback for claiming a file. */
- static enum ld_plugin_status
- register_claim_file(ld_plugin_claim_file_handler handler)
- {
- claim_file_handler = handler;
- return LDPS_OK;
- }
- /* Register HANDLER as the callback to removing temporary files. */
- static enum ld_plugin_status
- register_cleanup (ld_plugin_cleanup_handler handler)
- {
- cleanup_handler = handler;
- return LDPS_OK;
- }
- /* For a file identified by HANDLE, add NSYMS symbols from SYMS. */
- static enum ld_plugin_status
- add_symbols (void *handle, int nsyms,
- const struct ld_plugin_symbol *syms)
- {
- int i;
- struct file_handle *h = (struct file_handle *) handle;
- h->nsyms = nsyms;
- h->syms = calloc (nsyms, sizeof (struct ld_plugin_symbol));
- assert (h->syms);
- for (i = 0; i < nsyms; i++)
- {
- h->syms[i] = syms[i];
- h->syms[i].name = strdup (h->syms[i].name);
- if (h->syms[i].version)
- h->syms[i].version = strdup (h->syms[i].version);
- if (h->syms[i].comdat_key)
- h->syms[i].comdat_key = strdup (h->syms[i].comdat_key);
- }
- return LDPS_OK;
- }
- struct ld_plugin_tv tv[] = {
- {LDPT_REGISTER_CLAIM_FILE_HOOK,
- {.tv_register_claim_file = register_claim_file}
- },
- {LDPT_ADD_SYMBOLS,
- {.tv_add_symbols = add_symbols}
- },
- {LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK,
- {.tv_register_all_symbols_read = register_all_symbols_read}
- },
- {LDPT_GET_SYMBOLS,
- {.tv_get_symbols = get_symbols}
- },
- {LDPT_REGISTER_CLEANUP_HOOK,
- {.tv_register_cleanup = register_cleanup}
- },
- {0, {0}}
- };
- /* Load a plugin from a file named NAME. */
- static void
- load_plugin (const char *name)
- {
- ld_plugin_onload onload;
- plugin_handle = dlopen (name, RTLD_LAZY);
- assert (plugin_handle != NULL);
- onload = dlsym (plugin_handle, "onload");
- assert (onload);
- onload (tv);
- assert (claim_file_handler);
- }
- /* Send object to the plugin. The file (archive or object) name is NAME.
- FD is an open file descriptor. The object data starts at OFFSET and is
- FILESIZE bytes long. */
- static void
- register_object (const char *name, int fd, off_t offset, off_t filesize)
- {
- int claimed;
- struct ld_plugin_input_file file;
- void *handle;
- num_file_handles++;
- all_file_handles = realloc (all_file_handles, num_file_handles
- * sizeof (struct file_handle *));
- assert (all_file_handles);
- all_file_handles[num_file_handles - 1] = calloc (1,
- sizeof (struct file_handle));
- handle = all_file_handles[num_file_handles - 1];
- assert (handle);
- file.name = (char *) name;
- file.fd = fd;
- file.offset = offset;
- file.filesize = filesize;
- file.handle = handle;
- claim_file_handler (&file, &claimed);
- }
- /* Send file named NAME to the plugin. */
- static void
- register_file (const char *name)
- {
- int fd = open (name, O_RDONLY);
- Elf *elf;
- assert (fd >= 0);
- elf = elf_begin (fd, ELF_C_READ, NULL);
- assert (elf);
- Elf_Kind kind = elf_kind (elf);
- assert (kind == ELF_K_ELF || kind == ELF_K_AR);
- if (kind == ELF_K_AR)
- {
- Elf *member = elf_begin (fd, ELF_C_READ, elf);
- while (member)
- {
- Elf_Arhdr *h = elf_getarhdr (member);
- assert (h);
- if (h->ar_name[0] != '/')
- {
- off_t offset = elf_getbase (member);
- register_object (name, fd, offset, h->ar_size);
- }
- Elf_Cmd cmd = elf_next (member);
- elf_end (member);
- member = elf_begin (fd, cmd, elf);
- }
- }
- else /* Single File */
- register_object (name, fd, 0, 0);
- elf_end (elf);
- }
- /* Fake symbol resolution for testing. */
- static void
- resolve (void)
- {
- unsigned j;
- for (j = 0; j < num_file_handles; j++)
- {
- struct file_handle *handle = all_file_handles[j];
- unsigned int nsyms = handle->nsyms;
- struct ld_plugin_symbol *syms = handle->syms;
- unsigned i;
- for (i = 0; i < nsyms; i++)
- {
- switch (syms[i].def)
- {
- case LDPK_DEF:
- case LDPK_WEAKDEF:
- case LDPK_COMMON:
- syms[i].resolution = LDPR_PREVAILING_DEF;
- break;
- case LDPK_UNDEF:
- case LDPK_WEAKUNDEF:
- syms[i].resolution = LDPR_RESOLVED_IR;
- break;
- }
- }
- }
- }
- /* Print all symbol information. */
- static void
- print (void)
- {
- unsigned j;
- for (j = 0; j < num_file_handles; j++)
- {
- struct file_handle *handle = all_file_handles[j];
- unsigned int nsyms = handle->nsyms;
- struct ld_plugin_symbol *syms = handle->syms;
- unsigned i;
- for (i = 0; i < nsyms; i++)
- {
- printf("name: %s; ", syms[i].name);
- if (syms[i].version)
- printf("version: %s;", syms[i].version);
- else
- printf("not versioned; ");
- printf("kind: %s; ", lto_kind_str[syms[i].def]);
- printf("visibility: %s; ", lto_visibility_str[syms[i].visibility]);
- printf("size: %" PRId64 "; ", syms[i].size);
- if (syms[i].comdat_key)
- printf("comdat_key: %s; ", syms[i].comdat_key);
- else
- printf("no comdat_key; ");
- printf ("resolution: %s\n", lto_resolution_str[syms[i].resolution]);
- }
- }
- }
- /* Unload the plugin. */
- static void
- unload_plugin (void)
- {
- unsigned err = dlclose (plugin_handle);
- assert (err == 0);
- claim_file_handler = 0;
- all_symbols_read_handler = 0;
- }
- /* Free all memory allocated by us that hasn't been freed yet. */
- static void
- free_all (void)
- {
- unsigned j;
- for (j = 0; j < num_file_handles; j++)
- {
- struct file_handle *handle = all_file_handles[j];
- unsigned int nsyms = handle->nsyms;
- struct ld_plugin_symbol *syms = handle->syms;
- unsigned i;
- for (i = 0; i < nsyms; i++)
- {
- free (syms[i].name);
- syms[i].name = 0;
- if (syms[i].version)
- {
- free (syms[i].version);
- syms[i].version = 0;
- }
- if (syms[i].comdat_key)
- {
- free (syms[i].comdat_key);
- syms[i].comdat_key = 0;
- }
- }
- free (syms);
- handle->syms = NULL;
- handle->nsyms = 0;
- free (all_file_handles[j]);
- all_file_handles[j] = NULL;
- }
- free (all_file_handles);
- all_file_handles = NULL;
- num_file_handles = 0;
- }
- int
- main(int argc, char *argv[])
- {
- const char *plugin;
- unsigned int i;
- assert (argc >= 3);
- plugin = argv[1];
- load_plugin (plugin);
- for (i = 2; i < argc; i++)
- register_file (argv[i]);
- resolve ();
- print ();
- all_symbols_read_handler ();
- free_all ();
- cleanup_handler ();
- unload_plugin ();
- return 0;
- }
|