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