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
built_source_types(Elf * elf,char const * file)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
read_file(Elf * elf,char * file,char * label,read_cb_f * func,void * arg,int require_ctf)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
read_archive(int fd,Elf * elf,char * file,char * label,read_cb_f * func,void * arg,int require_ctf)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
read_ctf_common(char * file,char * label,read_cb_f * func,void * arg,int require_ctf)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
read_ctf_save_cb(tdata_t * td,char * name,void * retp)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
read_ctf(char ** files,int n,char * label,read_cb_f * func,void * private,int require_ctf)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
count_archive(int fd,Elf * elf,char * file)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
count_files(char ** files,int n)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 *
symit_new(Elf * elf,const char * file)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
symit_free(symit_data_t * si)368 symit_free(symit_data_t *si)
369 {
370 free(si);
371 }
372
373 void
symit_reset(symit_data_t * si)374 symit_reset(symit_data_t *si)
375 {
376 si->si_next = 0;
377 }
378
379 char *
symit_curfile(symit_data_t * si)380 symit_curfile(symit_data_t *si)
381 {
382 return (si->si_curfile);
383 }
384
385 GElf_Sym *
symit_next(symit_data_t * si,int type)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 *
symit_name(symit_data_t * si)415 symit_name(symit_data_t *si)
416 {
417 return (si->si_curname);
418 }
419