]>
Commit | Line | Data |
---|---|---|
d7f09764 DN |
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 | } |