OSDN Git Service

Backported from mainline
[pf3gnuchains/gcc-fork.git] / lto-plugin / lto-symtab.c
1 /* Program to read the IL symbol table.
2    Copyright (C) 2008 Free Software Foundation, Inc.
3    Contributed by Rafael Avila de Espindola (espindola@google.com).
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
18
19 #include <fcntl.h>
20 #include <assert.h>
21 #include <dlfcn.h>
22 #include <stdio.h>
23 #include <inttypes.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include "plugin-api.h"
28 #include "../gcc/lto/common.h"
29
30 /* The presence of gelf.h is checked by the toplevel configure script.  */
31 # include <gelf.h>
32
33 static ld_plugin_claim_file_handler claim_file_handler;
34 static ld_plugin_all_symbols_read_handler all_symbols_read_handler;
35 static ld_plugin_cleanup_handler cleanup_handler;
36 static void *plugin_handle;
37
38 struct file_handle {
39   unsigned nsyms;
40   struct ld_plugin_symbol *syms;
41 };
42
43 static struct file_handle **all_file_handles = NULL;
44 static unsigned int num_file_handles;
45
46 /* Write NSYMS symbols from file HANDLE in SYMS. */
47
48 static enum ld_plugin_status
49 get_symbols (const void *handle, int nsyms, struct ld_plugin_symbol *syms)
50 {
51   unsigned i;
52   struct file_handle *h = (struct file_handle *) handle;
53   assert (h->nsyms == nsyms);
54
55   for (i = 0; i < nsyms; i++)
56     syms[i] = h->syms[i];
57
58   return LDPS_OK;
59 }
60
61 /* Register HANDLER as the callback for notifying the plugin that all symbols
62    have been read. */
63
64 static enum ld_plugin_status
65 register_all_symbols_read (ld_plugin_all_symbols_read_handler handler)
66 {
67   all_symbols_read_handler = handler;
68   return LDPS_OK;
69 }
70
71 /* Register HANDLER as the callback for claiming a file. */
72
73 static enum ld_plugin_status
74 register_claim_file(ld_plugin_claim_file_handler handler)
75 {
76   claim_file_handler = handler;
77   return LDPS_OK;
78 }
79
80 /* Register HANDLER as the callback to removing temporary files. */
81
82 static enum ld_plugin_status
83 register_cleanup (ld_plugin_cleanup_handler handler)
84 {
85   cleanup_handler = handler;
86   return LDPS_OK;
87 }
88
89 /* For a file identified by HANDLE, add NSYMS symbols from SYMS. */
90
91 static enum ld_plugin_status
92 add_symbols (void *handle, int nsyms,
93              const struct ld_plugin_symbol *syms)
94 {
95   int i;
96   struct file_handle *h = (struct file_handle *) handle;
97   h->nsyms = nsyms;
98   h->syms = calloc (nsyms, sizeof (struct ld_plugin_symbol));
99   assert (h->syms);
100
101   for (i = 0; i < nsyms; i++)
102     {
103       h->syms[i] = syms[i];
104       h->syms[i].name = strdup (h->syms[i].name);
105       if (h->syms[i].version)
106         h->syms[i].version = strdup (h->syms[i].version);
107       if (h->syms[i].comdat_key)
108         h->syms[i].comdat_key = strdup (h->syms[i].comdat_key);
109     }
110
111   return LDPS_OK;
112 }
113
114 struct ld_plugin_tv tv[] = {
115   {LDPT_REGISTER_CLAIM_FILE_HOOK,
116    {.tv_register_claim_file = register_claim_file}
117   },
118   {LDPT_ADD_SYMBOLS,
119    {.tv_add_symbols = add_symbols}
120   },
121
122   {LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK,
123    {.tv_register_all_symbols_read = register_all_symbols_read}
124   },
125   {LDPT_GET_SYMBOLS,
126    {.tv_get_symbols = get_symbols}
127   },
128   {LDPT_REGISTER_CLEANUP_HOOK,
129    {.tv_register_cleanup = register_cleanup}
130   },
131   {0, {0}}
132 };
133
134 /* Load a plugin from a file named NAME. */
135
136 static void
137 load_plugin (const char *name)
138 {
139   ld_plugin_onload onload;
140   plugin_handle = dlopen (name, RTLD_LAZY);
141
142   assert (plugin_handle != NULL);
143   onload = dlsym (plugin_handle, "onload");
144   assert (onload);
145   onload (tv);
146   assert (claim_file_handler);
147 }
148
149 /* Send object to the plugin. The file (archive or object) name is NAME.
150    FD is an open file descriptor. The object data starts at OFFSET and is
151    FILESIZE bytes long. */
152
153 static void
154 register_object (const char *name, int fd, off_t offset, off_t filesize)
155 {
156   int claimed;
157   struct ld_plugin_input_file file;
158   void *handle;
159
160   num_file_handles++;
161   all_file_handles = realloc (all_file_handles, num_file_handles
162                               * sizeof (struct file_handle *));
163   assert (all_file_handles);
164
165   all_file_handles[num_file_handles - 1] = calloc (1,
166                                                    sizeof (struct file_handle));
167   handle = all_file_handles[num_file_handles - 1];
168   assert (handle);
169
170   file.name = (char *) name;
171   file.fd = fd;
172   file.offset = offset;
173   file.filesize = filesize;
174
175   file.handle = handle;
176
177   claim_file_handler (&file, &claimed);
178 }
179
180 /* Send file named NAME to the plugin. */
181
182 static void
183 register_file (const char *name)
184 {
185  int fd = open (name, O_RDONLY);
186  Elf *elf;
187
188  assert (fd >= 0);
189
190  elf = elf_begin (fd, ELF_C_READ, NULL);
191  assert (elf);
192
193  Elf_Kind kind = elf_kind (elf);
194
195  assert (kind == ELF_K_ELF || kind == ELF_K_AR);
196
197  if (kind == ELF_K_AR)
198    {
199      Elf *member = elf_begin (fd, ELF_C_READ, elf);
200      while (member)
201        {
202          Elf_Arhdr *h = elf_getarhdr (member);
203          assert (h);
204
205          if (h->ar_name[0] != '/')
206            {
207              off_t offset = elf_getbase (member);
208              register_object (name, fd, offset, h->ar_size);
209            }
210
211          Elf_Cmd cmd = elf_next (member);
212          elf_end (member);
213          member = elf_begin (fd, cmd, elf);
214        }
215    }
216  else /* Single File */
217    register_object (name, fd, 0, 0);
218
219  elf_end (elf);
220 }
221
222 /* Fake symbol resolution for testing. */
223
224 static void
225 resolve (void)
226 {
227   unsigned j;
228   for (j = 0; j < num_file_handles; j++)
229     {
230       struct file_handle *handle = all_file_handles[j];
231       unsigned int nsyms = handle->nsyms;
232       struct ld_plugin_symbol *syms = handle->syms;
233       unsigned i;
234       for (i = 0; i < nsyms; i++)
235         {
236           switch (syms[i].def)
237             {
238             case LDPK_DEF:
239             case LDPK_WEAKDEF:
240             case LDPK_COMMON:
241               syms[i].resolution =  LDPR_PREVAILING_DEF;
242               break;
243             case LDPK_UNDEF:
244             case LDPK_WEAKUNDEF:
245               syms[i].resolution =  LDPR_RESOLVED_IR;
246               break;
247             }
248         }
249     }
250 }
251
252 /* Print all symbol information. */
253
254 static void
255 print (void)
256 {
257   unsigned j;
258   for (j = 0; j < num_file_handles; j++)
259     {
260       struct file_handle *handle = all_file_handles[j];
261       unsigned int nsyms = handle->nsyms;
262       struct ld_plugin_symbol *syms = handle->syms;
263       unsigned i;
264       for (i = 0; i < nsyms; i++)
265         {
266           printf("name: %s; ", syms[i].name);
267           if (syms[i].version)
268              printf("version: %s;", syms[i].version);
269           else
270             printf("not versioned; ");
271           printf("kind: %s; ", lto_kind_str[syms[i].def]);
272           printf("visibility: %s; ", lto_visibility_str[syms[i].visibility]);
273           printf("size: %" PRId64 "; ", syms[i].size);
274           if (syms[i].comdat_key)
275             printf("comdat_key: %s; ", syms[i].comdat_key);
276           else
277             printf("no comdat_key; ");
278           printf ("resolution: %s\n", lto_resolution_str[syms[i].resolution]);
279         }
280     }
281 }
282
283 /* Unload the plugin. */
284
285 static void
286 unload_plugin (void)
287 {
288   unsigned err = dlclose (plugin_handle);
289   assert (err == 0);
290   claim_file_handler = 0;
291   all_symbols_read_handler = 0;
292 }
293
294 /* Free all memory allocated by us that hasn't been freed yet. */
295
296 static void
297 free_all (void)
298 {
299   unsigned j;
300   for (j = 0; j < num_file_handles; j++)
301     {
302       struct file_handle *handle = all_file_handles[j];
303       unsigned int nsyms = handle->nsyms;
304       struct ld_plugin_symbol *syms = handle->syms;
305       unsigned i;
306       for (i = 0; i < nsyms; i++)
307         {
308           free (syms[i].name);
309           syms[i].name = 0;
310           if (syms[i].version)
311             {
312               free (syms[i].version);
313               syms[i].version = 0;
314             }
315           if (syms[i].comdat_key)
316             {
317               free (syms[i].comdat_key);
318               syms[i].comdat_key = 0;
319             }
320         }
321       free (syms);
322       handle->syms = NULL;
323       handle->nsyms = 0;
324       free (all_file_handles[j]);
325       all_file_handles[j] = NULL;
326     }
327
328   free (all_file_handles);
329   all_file_handles = NULL;
330   num_file_handles = 0;
331 }
332
333 int
334 main(int argc, char *argv[])
335 {
336   const char *plugin;
337   unsigned int i;
338   assert (argc >= 3);
339   plugin = argv[1];
340
341   load_plugin (plugin);
342
343   for (i = 2; i < argc; i++)
344     register_file (argv[i]);
345
346   resolve ();
347
348   print ();
349
350   all_symbols_read_handler ();
351
352   free_all ();
353
354   cleanup_handler ();
355
356   unload_plugin ();
357
358   return 0;
359 }