163d1a8abSmrg /* Program to read the IL symbol table.
2*c7a68eb7Smrg Copyright (C) 2008-2018 Free Software Foundation, Inc.
363d1a8abSmrg Contributed by Rafael Avila de Espindola (espindola@google.com).
463d1a8abSmrg
563d1a8abSmrg This program is free software; you can redistribute it and/or modify
663d1a8abSmrg it under the terms of the GNU General Public License as published by
763d1a8abSmrg the Free Software Foundation; either version 3 of the License, or
863d1a8abSmrg (at your option) any later version.
963d1a8abSmrg
1063d1a8abSmrg This program is distributed in the hope that it will be useful,
1163d1a8abSmrg but WITHOUT ANY WARRANTY; without even the implied warranty of
1263d1a8abSmrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1363d1a8abSmrg GNU General Public License for more details.
1463d1a8abSmrg
1563d1a8abSmrg You should have received a copy of the GNU General Public License
1663d1a8abSmrg along with this program; if not, write to the Free Software
1763d1a8abSmrg Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
1863d1a8abSmrg
1963d1a8abSmrg #include <fcntl.h>
2063d1a8abSmrg #include <assert.h>
2163d1a8abSmrg #include <dlfcn.h>
2263d1a8abSmrg #include <stdio.h>
2363d1a8abSmrg #include <inttypes.h>
2463d1a8abSmrg #include <stdlib.h>
2563d1a8abSmrg #include <string.h>
2663d1a8abSmrg
2763d1a8abSmrg #include "plugin-api.h"
2863d1a8abSmrg #include "../gcc/lto/common.h"
2963d1a8abSmrg
3063d1a8abSmrg /* The presence of gelf.h is checked by the toplevel configure script. */
3163d1a8abSmrg # include <gelf.h>
3263d1a8abSmrg
3363d1a8abSmrg static ld_plugin_claim_file_handler claim_file_handler;
3463d1a8abSmrg static ld_plugin_all_symbols_read_handler all_symbols_read_handler;
3563d1a8abSmrg static ld_plugin_cleanup_handler cleanup_handler;
3663d1a8abSmrg static void *plugin_handle;
3763d1a8abSmrg
3863d1a8abSmrg struct file_handle {
3963d1a8abSmrg unsigned nsyms;
4063d1a8abSmrg struct ld_plugin_symbol *syms;
4163d1a8abSmrg };
4263d1a8abSmrg
4363d1a8abSmrg static struct file_handle **all_file_handles = NULL;
4463d1a8abSmrg static unsigned int num_file_handles;
4563d1a8abSmrg
4663d1a8abSmrg /* Write NSYMS symbols from file HANDLE in SYMS. */
4763d1a8abSmrg
4863d1a8abSmrg static enum ld_plugin_status
get_symbols(const void * handle,int nsyms,struct ld_plugin_symbol * syms)4963d1a8abSmrg get_symbols (const void *handle, int nsyms, struct ld_plugin_symbol *syms)
5063d1a8abSmrg {
5163d1a8abSmrg unsigned i;
5263d1a8abSmrg struct file_handle *h = (struct file_handle *) handle;
5363d1a8abSmrg assert (h->nsyms == nsyms);
5463d1a8abSmrg
5563d1a8abSmrg for (i = 0; i < nsyms; i++)
5663d1a8abSmrg syms[i] = h->syms[i];
5763d1a8abSmrg
5863d1a8abSmrg return LDPS_OK;
5963d1a8abSmrg }
6063d1a8abSmrg
6163d1a8abSmrg /* Register HANDLER as the callback for notifying the plugin that all symbols
6263d1a8abSmrg have been read. */
6363d1a8abSmrg
6463d1a8abSmrg static enum ld_plugin_status
register_all_symbols_read(ld_plugin_all_symbols_read_handler handler)6563d1a8abSmrg register_all_symbols_read (ld_plugin_all_symbols_read_handler handler)
6663d1a8abSmrg {
6763d1a8abSmrg all_symbols_read_handler = handler;
6863d1a8abSmrg return LDPS_OK;
6963d1a8abSmrg }
7063d1a8abSmrg
7163d1a8abSmrg /* Register HANDLER as the callback for claiming a file. */
7263d1a8abSmrg
7363d1a8abSmrg static enum ld_plugin_status
register_claim_file(ld_plugin_claim_file_handler handler)7463d1a8abSmrg register_claim_file(ld_plugin_claim_file_handler handler)
7563d1a8abSmrg {
7663d1a8abSmrg claim_file_handler = handler;
7763d1a8abSmrg return LDPS_OK;
7863d1a8abSmrg }
7963d1a8abSmrg
8063d1a8abSmrg /* Register HANDLER as the callback to removing temporary files. */
8163d1a8abSmrg
8263d1a8abSmrg static enum ld_plugin_status
register_cleanup(ld_plugin_cleanup_handler handler)8363d1a8abSmrg register_cleanup (ld_plugin_cleanup_handler handler)
8463d1a8abSmrg {
8563d1a8abSmrg cleanup_handler = handler;
8663d1a8abSmrg return LDPS_OK;
8763d1a8abSmrg }
8863d1a8abSmrg
8963d1a8abSmrg /* For a file identified by HANDLE, add NSYMS symbols from SYMS. */
9063d1a8abSmrg
9163d1a8abSmrg static enum ld_plugin_status
add_symbols(void * handle,int nsyms,const struct ld_plugin_symbol * syms)9263d1a8abSmrg add_symbols (void *handle, int nsyms,
9363d1a8abSmrg const struct ld_plugin_symbol *syms)
9463d1a8abSmrg {
9563d1a8abSmrg int i;
9663d1a8abSmrg struct file_handle *h = (struct file_handle *) handle;
9763d1a8abSmrg h->nsyms = nsyms;
9863d1a8abSmrg h->syms = calloc (nsyms, sizeof (struct ld_plugin_symbol));
9963d1a8abSmrg assert (h->syms);
10063d1a8abSmrg
10163d1a8abSmrg for (i = 0; i < nsyms; i++)
10263d1a8abSmrg {
10363d1a8abSmrg h->syms[i] = syms[i];
10463d1a8abSmrg h->syms[i].name = strdup (h->syms[i].name);
10563d1a8abSmrg if (h->syms[i].version)
10663d1a8abSmrg h->syms[i].version = strdup (h->syms[i].version);
10763d1a8abSmrg if (h->syms[i].comdat_key)
10863d1a8abSmrg h->syms[i].comdat_key = strdup (h->syms[i].comdat_key);
10963d1a8abSmrg }
11063d1a8abSmrg
11163d1a8abSmrg return LDPS_OK;
11263d1a8abSmrg }
11363d1a8abSmrg
11463d1a8abSmrg struct ld_plugin_tv tv[] = {
11563d1a8abSmrg {LDPT_REGISTER_CLAIM_FILE_HOOK,
11663d1a8abSmrg {.tv_register_claim_file = register_claim_file}
11763d1a8abSmrg },
11863d1a8abSmrg {LDPT_ADD_SYMBOLS,
11963d1a8abSmrg {.tv_add_symbols = add_symbols}
12063d1a8abSmrg },
12163d1a8abSmrg
12263d1a8abSmrg {LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK,
12363d1a8abSmrg {.tv_register_all_symbols_read = register_all_symbols_read}
12463d1a8abSmrg },
12563d1a8abSmrg {LDPT_GET_SYMBOLS,
12663d1a8abSmrg {.tv_get_symbols = get_symbols}
12763d1a8abSmrg },
12863d1a8abSmrg {LDPT_REGISTER_CLEANUP_HOOK,
12963d1a8abSmrg {.tv_register_cleanup = register_cleanup}
13063d1a8abSmrg },
13163d1a8abSmrg {0, {0}}
13263d1a8abSmrg };
13363d1a8abSmrg
13463d1a8abSmrg /* Load a plugin from a file named NAME. */
13563d1a8abSmrg
13663d1a8abSmrg static void
load_plugin(const char * name)13763d1a8abSmrg load_plugin (const char *name)
13863d1a8abSmrg {
13963d1a8abSmrg ld_plugin_onload onload;
14063d1a8abSmrg plugin_handle = dlopen (name, RTLD_LAZY);
14163d1a8abSmrg
14263d1a8abSmrg assert (plugin_handle != NULL);
14363d1a8abSmrg onload = dlsym (plugin_handle, "onload");
14463d1a8abSmrg assert (onload);
14563d1a8abSmrg onload (tv);
14663d1a8abSmrg assert (claim_file_handler);
14763d1a8abSmrg }
14863d1a8abSmrg
14963d1a8abSmrg /* Send object to the plugin. The file (archive or object) name is NAME.
15063d1a8abSmrg FD is an open file descriptor. The object data starts at OFFSET and is
15163d1a8abSmrg FILESIZE bytes long. */
15263d1a8abSmrg
15363d1a8abSmrg static void
register_object(const char * name,int fd,off_t offset,off_t filesize)15463d1a8abSmrg register_object (const char *name, int fd, off_t offset, off_t filesize)
15563d1a8abSmrg {
15663d1a8abSmrg int claimed;
15763d1a8abSmrg struct ld_plugin_input_file file;
15863d1a8abSmrg void *handle;
15963d1a8abSmrg
16063d1a8abSmrg num_file_handles++;
16163d1a8abSmrg all_file_handles = realloc (all_file_handles, num_file_handles
16263d1a8abSmrg * sizeof (struct file_handle *));
16363d1a8abSmrg assert (all_file_handles);
16463d1a8abSmrg
16563d1a8abSmrg all_file_handles[num_file_handles - 1] = calloc (1,
16663d1a8abSmrg sizeof (struct file_handle));
16763d1a8abSmrg handle = all_file_handles[num_file_handles - 1];
16863d1a8abSmrg assert (handle);
16963d1a8abSmrg
17063d1a8abSmrg file.name = (char *) name;
17163d1a8abSmrg file.fd = fd;
17263d1a8abSmrg file.offset = offset;
17363d1a8abSmrg file.filesize = filesize;
17463d1a8abSmrg
17563d1a8abSmrg file.handle = handle;
17663d1a8abSmrg
17763d1a8abSmrg claim_file_handler (&file, &claimed);
17863d1a8abSmrg }
17963d1a8abSmrg
18063d1a8abSmrg /* Send file named NAME to the plugin. */
18163d1a8abSmrg
18263d1a8abSmrg static void
register_file(const char * name)18363d1a8abSmrg register_file (const char *name)
18463d1a8abSmrg {
18563d1a8abSmrg int fd = open (name, O_RDONLY);
18663d1a8abSmrg Elf *elf;
18763d1a8abSmrg
18863d1a8abSmrg assert (fd >= 0);
18963d1a8abSmrg
19063d1a8abSmrg elf = elf_begin (fd, ELF_C_READ, NULL);
19163d1a8abSmrg assert (elf);
19263d1a8abSmrg
19363d1a8abSmrg Elf_Kind kind = elf_kind (elf);
19463d1a8abSmrg
19563d1a8abSmrg assert (kind == ELF_K_ELF || kind == ELF_K_AR);
19663d1a8abSmrg
19763d1a8abSmrg if (kind == ELF_K_AR)
19863d1a8abSmrg {
19963d1a8abSmrg Elf *member = elf_begin (fd, ELF_C_READ, elf);
20063d1a8abSmrg while (member)
20163d1a8abSmrg {
20263d1a8abSmrg Elf_Arhdr *h = elf_getarhdr (member);
20363d1a8abSmrg assert (h);
20463d1a8abSmrg
20563d1a8abSmrg if (h->ar_name[0] != '/')
20663d1a8abSmrg {
20763d1a8abSmrg off_t offset = elf_getbase (member);
20863d1a8abSmrg register_object (name, fd, offset, h->ar_size);
20963d1a8abSmrg }
21063d1a8abSmrg
21163d1a8abSmrg Elf_Cmd cmd = elf_next (member);
21263d1a8abSmrg elf_end (member);
21363d1a8abSmrg member = elf_begin (fd, cmd, elf);
21463d1a8abSmrg }
21563d1a8abSmrg }
21663d1a8abSmrg else /* Single File */
21763d1a8abSmrg register_object (name, fd, 0, 0);
21863d1a8abSmrg
21963d1a8abSmrg elf_end (elf);
22063d1a8abSmrg }
22163d1a8abSmrg
22263d1a8abSmrg /* Fake symbol resolution for testing. */
22363d1a8abSmrg
22463d1a8abSmrg static void
resolve(void)22563d1a8abSmrg resolve (void)
22663d1a8abSmrg {
22763d1a8abSmrg unsigned j;
22863d1a8abSmrg for (j = 0; j < num_file_handles; j++)
22963d1a8abSmrg {
23063d1a8abSmrg struct file_handle *handle = all_file_handles[j];
23163d1a8abSmrg unsigned int nsyms = handle->nsyms;
23263d1a8abSmrg struct ld_plugin_symbol *syms = handle->syms;
23363d1a8abSmrg unsigned i;
23463d1a8abSmrg for (i = 0; i < nsyms; i++)
23563d1a8abSmrg {
23663d1a8abSmrg switch (syms[i].def)
23763d1a8abSmrg {
23863d1a8abSmrg case LDPK_DEF:
23963d1a8abSmrg case LDPK_WEAKDEF:
24063d1a8abSmrg case LDPK_COMMON:
24163d1a8abSmrg syms[i].resolution = LDPR_PREVAILING_DEF;
24263d1a8abSmrg break;
24363d1a8abSmrg case LDPK_UNDEF:
24463d1a8abSmrg case LDPK_WEAKUNDEF:
24563d1a8abSmrg syms[i].resolution = LDPR_RESOLVED_IR;
24663d1a8abSmrg break;
24763d1a8abSmrg }
24863d1a8abSmrg }
24963d1a8abSmrg }
25063d1a8abSmrg }
25163d1a8abSmrg
25263d1a8abSmrg /* Print all symbol information. */
25363d1a8abSmrg
25463d1a8abSmrg static void
print(void)25563d1a8abSmrg print (void)
25663d1a8abSmrg {
25763d1a8abSmrg unsigned j;
25863d1a8abSmrg for (j = 0; j < num_file_handles; j++)
25963d1a8abSmrg {
26063d1a8abSmrg struct file_handle *handle = all_file_handles[j];
26163d1a8abSmrg unsigned int nsyms = handle->nsyms;
26263d1a8abSmrg struct ld_plugin_symbol *syms = handle->syms;
26363d1a8abSmrg unsigned i;
26463d1a8abSmrg for (i = 0; i < nsyms; i++)
26563d1a8abSmrg {
26663d1a8abSmrg printf("name: %s; ", syms[i].name);
26763d1a8abSmrg if (syms[i].version)
26863d1a8abSmrg printf("version: %s;", syms[i].version);
26963d1a8abSmrg else
27063d1a8abSmrg printf("not versioned; ");
27163d1a8abSmrg printf("kind: %s; ", lto_kind_str[syms[i].def]);
27263d1a8abSmrg printf("visibility: %s; ", lto_visibility_str[syms[i].visibility]);
27363d1a8abSmrg printf("size: %" PRId64 "; ", syms[i].size);
27463d1a8abSmrg if (syms[i].comdat_key)
27563d1a8abSmrg printf("comdat_key: %s; ", syms[i].comdat_key);
27663d1a8abSmrg else
27763d1a8abSmrg printf("no comdat_key; ");
27863d1a8abSmrg printf ("resolution: %s\n", lto_resolution_str[syms[i].resolution]);
27963d1a8abSmrg }
28063d1a8abSmrg }
28163d1a8abSmrg }
28263d1a8abSmrg
28363d1a8abSmrg /* Unload the plugin. */
28463d1a8abSmrg
28563d1a8abSmrg static void
unload_plugin(void)28663d1a8abSmrg unload_plugin (void)
28763d1a8abSmrg {
28863d1a8abSmrg unsigned err = dlclose (plugin_handle);
28963d1a8abSmrg assert (err == 0);
29063d1a8abSmrg claim_file_handler = 0;
29163d1a8abSmrg all_symbols_read_handler = 0;
29263d1a8abSmrg }
29363d1a8abSmrg
29463d1a8abSmrg /* Free all memory allocated by us that hasn't been freed yet. */
29563d1a8abSmrg
29663d1a8abSmrg static void
free_all(void)29763d1a8abSmrg free_all (void)
29863d1a8abSmrg {
29963d1a8abSmrg unsigned j;
30063d1a8abSmrg for (j = 0; j < num_file_handles; j++)
30163d1a8abSmrg {
30263d1a8abSmrg struct file_handle *handle = all_file_handles[j];
30363d1a8abSmrg unsigned int nsyms = handle->nsyms;
30463d1a8abSmrg struct ld_plugin_symbol *syms = handle->syms;
30563d1a8abSmrg unsigned i;
30663d1a8abSmrg for (i = 0; i < nsyms; i++)
30763d1a8abSmrg {
30863d1a8abSmrg free (syms[i].name);
30963d1a8abSmrg syms[i].name = 0;
31063d1a8abSmrg if (syms[i].version)
31163d1a8abSmrg {
31263d1a8abSmrg free (syms[i].version);
31363d1a8abSmrg syms[i].version = 0;
31463d1a8abSmrg }
31563d1a8abSmrg if (syms[i].comdat_key)
31663d1a8abSmrg {
31763d1a8abSmrg free (syms[i].comdat_key);
31863d1a8abSmrg syms[i].comdat_key = 0;
31963d1a8abSmrg }
32063d1a8abSmrg }
32163d1a8abSmrg free (syms);
32263d1a8abSmrg handle->syms = NULL;
32363d1a8abSmrg handle->nsyms = 0;
32463d1a8abSmrg free (all_file_handles[j]);
32563d1a8abSmrg all_file_handles[j] = NULL;
32663d1a8abSmrg }
32763d1a8abSmrg
32863d1a8abSmrg free (all_file_handles);
32963d1a8abSmrg all_file_handles = NULL;
33063d1a8abSmrg num_file_handles = 0;
33163d1a8abSmrg }
33263d1a8abSmrg
33363d1a8abSmrg int
main(int argc,char * argv[])33463d1a8abSmrg main(int argc, char *argv[])
33563d1a8abSmrg {
33663d1a8abSmrg const char *plugin;
33763d1a8abSmrg unsigned int i;
33863d1a8abSmrg assert (argc >= 3);
33963d1a8abSmrg plugin = argv[1];
34063d1a8abSmrg
34163d1a8abSmrg load_plugin (plugin);
34263d1a8abSmrg
34363d1a8abSmrg for (i = 2; i < argc; i++)
34463d1a8abSmrg register_file (argv[i]);
34563d1a8abSmrg
34663d1a8abSmrg resolve ();
34763d1a8abSmrg
34863d1a8abSmrg print ();
34963d1a8abSmrg
35063d1a8abSmrg all_symbols_read_handler ();
35163d1a8abSmrg
35263d1a8abSmrg free_all ();
35363d1a8abSmrg
35463d1a8abSmrg cleanup_handler ();
35563d1a8abSmrg
35663d1a8abSmrg unload_plugin ();
35763d1a8abSmrg
35863d1a8abSmrg return 0;
35963d1a8abSmrg }
360