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