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