xref: /titanic_50/usr/src/tools/ctf/cvt/input.c (revision 2df1fe9ca32bb227b9158c67f5c00b54c20b10fd)
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 			types |= SOURCE_S;
75 			break;
76 		default:
77 			types |= SOURCE_UNKNOWN;
78 		}
79 	}
80 
81 	symit_free(si);
82 	return (types);
83 }
84 
85 static int
86 read_file(Elf *elf, char *file, char *label, read_cb_f *func, void *arg,
87     int require_ctf)
88 {
89 	Elf_Scn *ctfscn;
90 	Elf_Data *ctfdata;
91 	symit_data_t *si = NULL;
92 	int ctfscnidx;
93 	tdata_t *td;
94 
95 	if ((ctfscnidx = findelfsecidx(elf, file, ".SUNW_ctf")) < 0) {
96 		if (require_ctf &&
97 		    (built_source_types(elf, file) & SOURCE_C)) {
98 			terminate("Input file %s was partially built from "
99 			    "C sources, but no CTF data was present\n", file);
100 		}
101 		return (0);
102 	}
103 
104 	if ((ctfscn = elf_getscn(elf, ctfscnidx)) == NULL ||
105 	    (ctfdata = elf_getdata(ctfscn, NULL)) == NULL)
106 		elfterminate(file, "Cannot read CTF section");
107 
108 	/* Reconstruction of type tree */
109 	if ((si = symit_new(elf, file)) == NULL) {
110 		warning("%s has no symbol table - skipping", file);
111 		return (0);
112 	}
113 
114 	td = ctf_load(file, ctfdata->d_buf, ctfdata->d_size, si, label);
115 	tdata_build_hashes(td);
116 
117 	symit_free(si);
118 
119 	if (td != NULL) {
120 		if (func(td, file, arg) < 0)
121 			return (-1);
122 		else
123 			return (1);
124 	}
125 	return (0);
126 }
127 
128 static int
129 read_archive(int fd, Elf *elf, char *file, char *label, read_cb_f *func,
130     void *arg, int require_ctf)
131 {
132 	Elf *melf;
133 	Elf_Cmd cmd = ELF_C_READ;
134 	Elf_Arhdr *arh;
135 	int secnum = 1, found = 0;
136 
137 	while ((melf = elf_begin(fd, cmd, elf)) != NULL) {
138 		int rc = 0;
139 
140 		if ((arh = elf_getarhdr(melf)) == NULL) {
141 			elfterminate(file, "Can't get archive header for "
142 			    "member %d", secnum);
143 		}
144 
145 		/* skip special sections - their names begin with "/" */
146 		if (*arh->ar_name != '/') {
147 			size_t memlen = strlen(file) + 1 +
148 			    strlen(arh->ar_name) + 1 + 1;
149 			char *memname = xmalloc(memlen);
150 
151 			snprintf(memname, memlen, "%s(%s)", file, arh->ar_name);
152 
153 			switch (elf_kind(melf)) {
154 			case ELF_K_AR:
155 				rc = read_archive(fd, melf, memname, label,
156 				    func, arg, require_ctf);
157 				break;
158 			case ELF_K_ELF:
159 				rc = read_file(melf, memname, label,
160 				    func, arg, require_ctf);
161 				break;
162 			default:
163 				terminate("%s: Unknown elf kind %d\n",
164 				    memname, elf_kind(melf));
165 			}
166 
167 			free(memname);
168 		}
169 
170 		cmd = elf_next(melf);
171 		(void) elf_end(melf);
172 		secnum++;
173 
174 		if (rc < 0)
175 			return (rc);
176 		else
177 			found += rc;
178 	}
179 
180 	return (found);
181 }
182 
183 static int
184 read_ctf_common(char *file, char *label, read_cb_f *func, void *arg,
185     int require_ctf)
186 {
187 	Elf *elf;
188 	int found = 0;
189 	int fd;
190 
191 	debug(3, "Reading %s (label %s)\n", file, (label ? label : "NONE"));
192 
193 	(void) elf_version(EV_CURRENT);
194 
195 	if ((fd = open(file, O_RDONLY)) < 0)
196 		terminate("%s: Cannot open for reading", file);
197 	if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
198 		elfterminate(file, "Cannot read");
199 
200 	switch (elf_kind(elf)) {
201 	case ELF_K_AR:
202 		found = read_archive(fd, elf, file, label,
203 		    func, arg, require_ctf);
204 		break;
205 
206 	case ELF_K_ELF:
207 		found = read_file(elf, file, label,
208 		    func, arg, require_ctf);
209 		break;
210 
211 	default:
212 		terminate("%s: Unknown elf kind %d\n", file, elf_kind(elf));
213 	}
214 
215 	(void) elf_end(elf);
216 	(void) close(fd);
217 
218 	return (found);
219 }
220 
221 /*ARGSUSED*/
222 int
223 read_ctf_save_cb(tdata_t *td, char *name, void *retp)
224 {
225 	tdata_t **tdp = retp;
226 
227 	*tdp = td;
228 
229 	return (1);
230 }
231 
232 int
233 read_ctf(char **files, int n, char *label, read_cb_f *func, void *private,
234     int require_ctf)
235 {
236 	int found;
237 	int i, rc;
238 
239 	for (i = 0, found = 0; i < n; i++) {
240 		if ((rc = read_ctf_common(files[i], label, func,
241 		    private, require_ctf)) < 0)
242 			return (rc);
243 		found += rc;
244 	}
245 
246 	return (found);
247 }
248 
249 static int
250 count_archive(int fd, Elf *elf, char *file)
251 {
252 	Elf *melf;
253 	Elf_Cmd cmd = ELF_C_READ;
254 	Elf_Arhdr *arh;
255 	int nfiles = 0, err = 0;
256 
257 	while ((melf = elf_begin(fd, cmd, elf)) != NULL) {
258 		if ((arh = elf_getarhdr(melf)) == NULL) {
259 			warning("Can't process input archive %s\n",
260 			    file);
261 			err++;
262 		}
263 
264 		if (*arh->ar_name != '/')
265 			nfiles++;
266 
267 		cmd = elf_next(melf);
268 		(void) elf_end(melf);
269 	}
270 
271 	if (err > 0)
272 		return (-1);
273 
274 	return (nfiles);
275 }
276 
277 int
278 count_files(char **files, int n)
279 {
280 	int nfiles = 0, err = 0;
281 	Elf *elf;
282 	int fd, rc, i;
283 
284 	(void) elf_version(EV_CURRENT);
285 
286 	for (i = 0; i < n; i++) {
287 		char *file = files[i];
288 
289 		if ((fd = open(file, O_RDONLY)) < 0) {
290 			warning("Can't read input file %s", file);
291 			err++;
292 			continue;
293 		}
294 
295 		if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
296 			warning("Can't open input file %s: %s\n", file,
297 			    elf_errmsg(-1));
298 			err++;
299 			(void) close(fd);
300 			continue;
301 		}
302 
303 		switch (elf_kind(elf)) {
304 		case ELF_K_AR:
305 			if ((rc = count_archive(fd, elf, file)) < 0)
306 				err++;
307 			else
308 				nfiles += rc;
309 			break;
310 		case ELF_K_ELF:
311 			nfiles++;
312 			break;
313 		default:
314 			warning("Input file %s is corrupt\n", file);
315 			err++;
316 		}
317 
318 		(void) elf_end(elf);
319 		(void) close(fd);
320 	}
321 
322 	if (err > 0)
323 		return (-1);
324 
325 	debug(2, "Found %d files in %d input files\n", nfiles, n);
326 
327 	return (nfiles);
328 }
329 
330 struct symit_data {
331 	GElf_Shdr si_shdr;
332 	Elf_Data *si_symd;
333 	Elf_Data *si_strd;
334 	GElf_Sym si_cursym;
335 	char *si_curname;
336 	char *si_curfile;
337 	int si_nument;
338 	int si_next;
339 };
340 
341 symit_data_t *
342 symit_new(Elf *elf, const char *file)
343 {
344 	symit_data_t *si;
345 	Elf_Scn *scn;
346 	int symtabidx;
347 
348 	if ((symtabidx = findelfsecidx(elf, file, ".symtab")) < 0)
349 		return (NULL);
350 
351 	si = xcalloc(sizeof (symit_data_t));
352 
353 	if ((scn = elf_getscn(elf, symtabidx)) == NULL ||
354 	    gelf_getshdr(scn, &si->si_shdr) == NULL ||
355 	    (si->si_symd = elf_getdata(scn, NULL)) == NULL)
356 		elfterminate(file, "Cannot read .symtab");
357 
358 	if ((scn = elf_getscn(elf, si->si_shdr.sh_link)) == NULL ||
359 	    (si->si_strd = elf_getdata(scn, NULL)) == NULL)
360 		elfterminate(file, "Cannot read strings for .symtab");
361 
362 	si->si_nument = si->si_shdr.sh_size / si->si_shdr.sh_entsize;
363 
364 	return (si);
365 }
366 
367 void
368 symit_free(symit_data_t *si)
369 {
370 	free(si);
371 }
372 
373 void
374 symit_reset(symit_data_t *si)
375 {
376 	si->si_next = 0;
377 }
378 
379 char *
380 symit_curfile(symit_data_t *si)
381 {
382 	return (si->si_curfile);
383 }
384 
385 GElf_Sym *
386 symit_next(symit_data_t *si, int type)
387 {
388 	GElf_Sym sym;
389 	int check_sym = (type == STT_OBJECT || type == STT_FUNC);
390 
391 	for (; si->si_next < si->si_nument; si->si_next++) {
392 		gelf_getsym(si->si_symd, si->si_next, &si->si_cursym);
393 		gelf_getsym(si->si_symd, si->si_next, &sym);
394 		si->si_curname = (caddr_t)si->si_strd->d_buf + sym.st_name;
395 
396 		if (GELF_ST_TYPE(sym.st_info) == STT_FILE)
397 			si->si_curfile = si->si_curname;
398 
399 		if (GELF_ST_TYPE(sym.st_info) != type ||
400 		    sym.st_shndx == SHN_UNDEF)
401 			continue;
402 
403 		if (check_sym && ignore_symbol(&sym, si->si_curname))
404 			continue;
405 
406 		si->si_next++;
407 
408 		return (&si->si_cursym);
409 	}
410 
411 	return (NULL);
412 }
413 
414 char *
415 symit_name(symit_data_t *si)
416 {
417 	return (si->si_curname);
418 }
419