]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - cddl/contrib/opensolaris/tools/ctf/cvt/input.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / cddl / contrib / opensolaris / tools / ctf / cvt / input.c
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25
26 #pragma ident   "%Z%%M% %I%     %E% SMI"
27
28 /*
29  * Routines for retrieving CTF data from a .SUNW_ctf ELF section
30  */
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36 #include <gelf.h>
37 #include <strings.h>
38 #include <sys/types.h>
39
40 #include "ctftools.h"
41 #include "memory.h"
42 #include "symbol.h"
43
44 typedef int read_cb_f(tdata_t *, char *, void *);
45
46 /*
47  * Return the source types that the object was generated from.
48  */
49 source_types_t
50 built_source_types(Elf *elf, char const *file)
51 {
52         source_types_t types = SOURCE_NONE;
53         symit_data_t *si;
54
55         if ((si = symit_new(elf, file)) == NULL)
56                 return (SOURCE_NONE);
57
58         while (symit_next(si, STT_FILE) != NULL) {
59                 char *name = symit_name(si);
60                 size_t len = strlen(name);
61                 if (len < 2 || name[len - 2] != '.') {
62                         types |= SOURCE_UNKNOWN;
63                         continue;
64                 }
65
66                 switch (name[len - 1]) {
67                 case 'c':
68                         types |= SOURCE_C;
69                         break;
70                 case 'h':
71                         /* ignore */
72                         break;
73                 case 's':
74                 case 'S':
75                         types |= SOURCE_S;
76                         break;
77                 default:
78                         types |= SOURCE_UNKNOWN;
79                 }
80         }
81
82         symit_free(si);
83         return (types);
84 }
85
86 static int
87 read_file(Elf *elf, char *file, char *label, read_cb_f *func, void *arg,
88     int require_ctf)
89 {
90         Elf_Scn *ctfscn;
91         Elf_Data *ctfdata = NULL;
92         symit_data_t *si = NULL;
93         int ctfscnidx;
94         tdata_t *td;
95
96         if ((ctfscnidx = findelfsecidx(elf, file, ".SUNW_ctf")) < 0) {
97                 if (require_ctf &&
98                     (built_source_types(elf, file) & SOURCE_C)) {
99                         terminate("Input file %s was partially built from "
100                             "C sources, but no CTF data was present\n", file);
101                 }
102                 return (0);
103         }
104
105         if ((ctfscn = elf_getscn(elf, ctfscnidx)) == NULL ||
106             (ctfdata = elf_getdata(ctfscn, NULL)) == NULL)
107                 elfterminate(file, "Cannot read CTF section");
108
109         /* Reconstruction of type tree */
110         if ((si = symit_new(elf, file)) == NULL) {
111                 warning("%s has no symbol table - skipping", file);
112                 return (0);
113         }
114
115         td = ctf_load(file, ctfdata->d_buf, ctfdata->d_size, si, label);
116         tdata_build_hashes(td);
117
118         symit_free(si);
119
120         if (td != NULL) {
121                 if (func(td, file, arg) < 0)
122                         return (-1);
123                 else
124                         return (1);
125         }
126         return (0);
127 }
128
129 static int
130 read_archive(int fd, Elf *elf, char *file, char *label, read_cb_f *func,
131     void *arg, int require_ctf)
132 {
133         Elf *melf;
134         Elf_Cmd cmd = ELF_C_READ;
135         Elf_Arhdr *arh;
136         int secnum = 1, found = 0;
137
138         while ((melf = elf_begin(fd, cmd, elf)) != NULL) {
139                 int rc = 0;
140
141                 if ((arh = elf_getarhdr(melf)) == NULL) {
142                         elfterminate(file, "Can't get archive header for "
143                             "member %d", secnum);
144                 }
145
146                 /* skip special sections - their names begin with "/" */
147                 if (*arh->ar_name != '/') {
148                         size_t memlen = strlen(file) + 1 +
149                             strlen(arh->ar_name) + 1 + 1;
150                         char *memname = xmalloc(memlen);
151
152                         snprintf(memname, memlen, "%s(%s)", file, arh->ar_name);
153
154                         switch (elf_kind(melf)) {
155                         case ELF_K_AR:
156                                 rc = read_archive(fd, melf, memname, label,
157                                     func, arg, require_ctf);
158                                 break;
159                         case ELF_K_ELF:
160                                 rc = read_file(melf, memname, label,
161                                     func, arg, require_ctf);
162                                 break;
163                         default:
164                                 terminate("%s: Unknown elf kind %d\n",
165                                     memname, elf_kind(melf));
166                         }
167
168                         free(memname);
169                 }
170
171                 cmd = elf_next(melf);
172                 (void) elf_end(melf);
173                 secnum++;
174
175                 if (rc < 0)
176                         return (rc);
177                 else
178                         found += rc;
179         }
180
181         return (found);
182 }
183
184 static int
185 read_ctf_common(char *file, char *label, read_cb_f *func, void *arg,
186     int require_ctf)
187 {
188         Elf *elf;
189         int found = 0;
190         int fd;
191
192         debug(3, "Reading %s (label %s)\n", file, (label ? label : "NONE"));
193
194         (void) elf_version(EV_CURRENT);
195
196         if ((fd = open(file, O_RDONLY)) < 0)
197                 terminate("%s: Cannot open for reading", file);
198         if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
199                 elfterminate(file, "Cannot read");
200
201         switch (elf_kind(elf)) {
202         case ELF_K_AR:
203                 found = read_archive(fd, elf, file, label,
204                     func, arg, require_ctf);
205                 break;
206
207         case ELF_K_ELF:
208                 found = read_file(elf, file, label,
209                     func, arg, require_ctf);
210                 break;
211
212         default:
213                 terminate("%s: Unknown elf kind %d\n", file, elf_kind(elf));
214         }
215
216         (void) elf_end(elf);
217         (void) close(fd);
218
219         return (found);
220 }
221
222 /*ARGSUSED*/
223 int
224 read_ctf_save_cb(tdata_t *td, char *name __unused, void *retp)
225 {
226         tdata_t **tdp = retp;
227
228         *tdp = td;
229
230         return (1);
231 }
232
233 int
234 read_ctf(char **files, int n, char *label, read_cb_f *func, void *private,
235     int require_ctf)
236 {
237         int found;
238         int i, rc;
239
240         for (i = 0, found = 0; i < n; i++) {
241                 if ((rc = read_ctf_common(files[i], label, func,
242                     private, require_ctf)) < 0)
243                         return (rc);
244                 found += rc;
245         }
246
247         return (found);
248 }
249
250 static int
251 count_archive(int fd, Elf *elf, char *file)
252 {
253         Elf *melf;
254         Elf_Cmd cmd = ELF_C_READ;
255         Elf_Arhdr *arh;
256         int nfiles = 0, err = 0;
257
258         while ((melf = elf_begin(fd, cmd, elf)) != NULL) {
259                 if ((arh = elf_getarhdr(melf)) == NULL) {
260                         warning("Can't process input archive %s\n",
261                             file);
262                         err++;
263                 }
264
265                 if (*arh->ar_name != '/')
266                         nfiles++;
267
268                 cmd = elf_next(melf);
269                 (void) elf_end(melf);
270         }
271
272         if (err > 0)
273                 return (-1);
274
275         return (nfiles);
276 }
277
278 int
279 count_files(char **files, int n)
280 {
281         int nfiles = 0, err = 0;
282         Elf *elf;
283         int fd, rc, i;
284
285         (void) elf_version(EV_CURRENT);
286
287         for (i = 0; i < n; i++) {
288                 char *file = files[i];
289
290                 if ((fd = open(file, O_RDONLY)) < 0) {
291                         warning("Can't read input file %s", file);
292                         err++;
293                         continue;
294                 }
295
296                 if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
297                         warning("Can't open input file %s: %s\n", file,
298                             elf_errmsg(-1));
299                         err++;
300                         (void) close(fd);
301                         continue;
302                 }
303
304                 switch (elf_kind(elf)) {
305                 case ELF_K_AR:
306                         if ((rc = count_archive(fd, elf, file)) < 0)
307                                 err++;
308                         else
309                                 nfiles += rc;
310                         break;
311                 case ELF_K_ELF:
312                         nfiles++;
313                         break;
314                 default:
315                         warning("Input file %s is corrupt\n", file);
316                         err++;
317                 }
318
319                 (void) elf_end(elf);
320                 (void) close(fd);
321         }
322
323         if (err > 0)
324                 return (-1);
325
326         debug(2, "Found %d files in %d input files\n", nfiles, n);
327
328         return (nfiles);
329 }
330
331 struct symit_data {
332         GElf_Shdr si_shdr;
333         Elf_Data *si_symd;
334         Elf_Data *si_strd;
335         GElf_Sym si_cursym;
336         char *si_curname;
337         char *si_curfile;
338         int si_nument;
339         int si_next;
340 };
341
342 symit_data_t *
343 symit_new(Elf *elf, const char *file)
344 {
345         symit_data_t *si;
346         Elf_Scn *scn;
347         int symtabidx;
348
349         if ((symtabidx = findelfsecidx(elf, file, ".symtab")) < 0)
350                 return (NULL);
351
352         si = xcalloc(sizeof (symit_data_t));
353
354         if ((scn = elf_getscn(elf, symtabidx)) == NULL ||
355             gelf_getshdr(scn, &si->si_shdr) == NULL ||
356             (si->si_symd = elf_getdata(scn, NULL)) == NULL)
357                 elfterminate(file, "Cannot read .symtab");
358
359         if ((scn = elf_getscn(elf, si->si_shdr.sh_link)) == NULL ||
360             (si->si_strd = elf_getdata(scn, NULL)) == NULL)
361                 elfterminate(file, "Cannot read strings for .symtab");
362
363         si->si_nument = si->si_shdr.sh_size / si->si_shdr.sh_entsize;
364
365         return (si);
366 }
367
368 void
369 symit_free(symit_data_t *si)
370 {
371         free(si);
372 }
373
374 void
375 symit_reset(symit_data_t *si)
376 {
377         si->si_next = 0;
378 }
379
380 char *
381 symit_curfile(symit_data_t *si)
382 {
383         return (si->si_curfile);
384 }
385
386 GElf_Sym *
387 symit_next(symit_data_t *si, int type)
388 {
389         GElf_Sym sym;
390         char *bname;
391         int check_sym = (type == STT_OBJECT || type == STT_FUNC);
392
393         for (; si->si_next < si->si_nument; si->si_next++) {
394                 gelf_getsym(si->si_symd, si->si_next, &si->si_cursym);
395                 gelf_getsym(si->si_symd, si->si_next, &sym);
396                 si->si_curname = (caddr_t)si->si_strd->d_buf + sym.st_name;
397
398                 if (GELF_ST_TYPE(sym.st_info) == STT_FILE) {
399                         bname = strrchr(si->si_curname, '/');
400                         si->si_curfile = bname == NULL ? si->si_curname : bname + 1;
401                 }
402
403                 if (GELF_ST_TYPE(sym.st_info) != type ||
404                     sym.st_shndx == SHN_UNDEF)
405                         continue;
406
407                 if (check_sym && ignore_symbol(&sym, si->si_curname))
408                         continue;
409
410                 si->si_next++;
411
412                 return (&si->si_cursym);
413         }
414
415         return (NULL);
416 }
417
418 char *
419 symit_name(symit_data_t *si)
420 {
421         return (si->si_curname);
422 }