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