17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5c168da27Sjohnlev * Common Development and Distribution License (the "License").
6c168da27Sjohnlev * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
22c168da27Sjohnlev * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate * Given a file containing sections with stabs data, convert the stabs data to
287c478bd9Sstevel@tonic-gate * CTF data, and replace the stabs sections with a CTF section.
297c478bd9Sstevel@tonic-gate */
307c478bd9Sstevel@tonic-gate
317c478bd9Sstevel@tonic-gate #include <stdio.h>
327c478bd9Sstevel@tonic-gate #include <stdlib.h>
337c478bd9Sstevel@tonic-gate #include <unistd.h>
347c478bd9Sstevel@tonic-gate #include <signal.h>
357c478bd9Sstevel@tonic-gate #include <string.h>
367c478bd9Sstevel@tonic-gate #include <fcntl.h>
377c478bd9Sstevel@tonic-gate #include <libgen.h>
387c478bd9Sstevel@tonic-gate #include <errno.h>
397c478bd9Sstevel@tonic-gate #include <assert.h>
407c478bd9Sstevel@tonic-gate
417c478bd9Sstevel@tonic-gate #include "ctftools.h"
427c478bd9Sstevel@tonic-gate #include "memory.h"
437c478bd9Sstevel@tonic-gate
447c478bd9Sstevel@tonic-gate const char *progname;
457c478bd9Sstevel@tonic-gate int debug_level = DEBUG_LEVEL;
467c478bd9Sstevel@tonic-gate
477c478bd9Sstevel@tonic-gate static const char *infile = NULL;
487c478bd9Sstevel@tonic-gate static const char *outfile = NULL;
497c478bd9Sstevel@tonic-gate static int dynsym;
507c478bd9Sstevel@tonic-gate
517c478bd9Sstevel@tonic-gate static void
usage(void)527c478bd9Sstevel@tonic-gate usage(void)
537c478bd9Sstevel@tonic-gate {
547c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
55*c79a74a8SRichard Lowe "Usage: %s [-is] -l label | -L labelenv [-o outfile] object_file\n"
567c478bd9Sstevel@tonic-gate "\n"
577c478bd9Sstevel@tonic-gate " Note: if -L labelenv is specified and labelenv is not set in\n"
587c478bd9Sstevel@tonic-gate " the environment, a default value is used.\n",
597c478bd9Sstevel@tonic-gate progname);
607c478bd9Sstevel@tonic-gate }
617c478bd9Sstevel@tonic-gate
627c478bd9Sstevel@tonic-gate static void
terminate_cleanup(void)637c478bd9Sstevel@tonic-gate terminate_cleanup(void)
647c478bd9Sstevel@tonic-gate {
657c478bd9Sstevel@tonic-gate if (!outfile) {
667c478bd9Sstevel@tonic-gate fprintf(stderr, "Removing %s\n", infile);
677c478bd9Sstevel@tonic-gate unlink(infile);
687c478bd9Sstevel@tonic-gate }
697c478bd9Sstevel@tonic-gate }
707c478bd9Sstevel@tonic-gate
717c478bd9Sstevel@tonic-gate static void
handle_sig(int sig)727c478bd9Sstevel@tonic-gate handle_sig(int sig)
737c478bd9Sstevel@tonic-gate {
747c478bd9Sstevel@tonic-gate terminate("Caught signal %d - exiting\n", sig);
757c478bd9Sstevel@tonic-gate }
767c478bd9Sstevel@tonic-gate
777c478bd9Sstevel@tonic-gate static int
file_read(tdata_t * td,const char * filename,int ignore_non_c)787c478bd9Sstevel@tonic-gate file_read(tdata_t *td, const char *filename, int ignore_non_c)
797c478bd9Sstevel@tonic-gate {
807c478bd9Sstevel@tonic-gate typedef int (*reader_f)(tdata_t *, Elf *, const char *);
817c478bd9Sstevel@tonic-gate static const reader_f readers[] = {
827c478bd9Sstevel@tonic-gate stabs_read,
837c478bd9Sstevel@tonic-gate dw_read,
847c478bd9Sstevel@tonic-gate NULL
857c478bd9Sstevel@tonic-gate };
867c478bd9Sstevel@tonic-gate
877c478bd9Sstevel@tonic-gate source_types_t source_types;
887c478bd9Sstevel@tonic-gate Elf *elf;
897c478bd9Sstevel@tonic-gate int i, rc, fd;
907c478bd9Sstevel@tonic-gate
917c478bd9Sstevel@tonic-gate if ((fd = open(filename, O_RDONLY)) < 0)
927c478bd9Sstevel@tonic-gate terminate("failed to open %s", filename);
937c478bd9Sstevel@tonic-gate
947c478bd9Sstevel@tonic-gate (void) elf_version(EV_CURRENT);
957c478bd9Sstevel@tonic-gate
967c478bd9Sstevel@tonic-gate if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
977c478bd9Sstevel@tonic-gate close(fd);
987c478bd9Sstevel@tonic-gate terminate("failed to read %s: %s\n", filename,
99c168da27Sjohnlev elf_errmsg(-1));
1007c478bd9Sstevel@tonic-gate }
1017c478bd9Sstevel@tonic-gate
1027c478bd9Sstevel@tonic-gate source_types = built_source_types(elf, filename);
1037c478bd9Sstevel@tonic-gate
1047c478bd9Sstevel@tonic-gate if ((source_types == SOURCE_NONE || (source_types & SOURCE_UNKNOWN)) &&
1057c478bd9Sstevel@tonic-gate ignore_non_c) {
1067c478bd9Sstevel@tonic-gate debug(1, "Ignoring file %s from unknown sources\n", filename);
1077c478bd9Sstevel@tonic-gate exit(0);
1087c478bd9Sstevel@tonic-gate }
1097c478bd9Sstevel@tonic-gate
1107c478bd9Sstevel@tonic-gate for (i = 0; readers[i] != NULL; i++) {
1117c478bd9Sstevel@tonic-gate if ((rc = readers[i](td, elf, filename)) == 0)
1127c478bd9Sstevel@tonic-gate break;
1137c478bd9Sstevel@tonic-gate
1147c478bd9Sstevel@tonic-gate assert(rc < 0 && errno == ENOENT);
1157c478bd9Sstevel@tonic-gate }
1167c478bd9Sstevel@tonic-gate
1177c478bd9Sstevel@tonic-gate if (readers[i] == NULL) {
1187c478bd9Sstevel@tonic-gate /*
1197c478bd9Sstevel@tonic-gate * None of the readers found compatible type data.
1207c478bd9Sstevel@tonic-gate */
1217c478bd9Sstevel@tonic-gate
122c168da27Sjohnlev if (findelfsecidx(elf, filename, ".debug") >= 0) {
123c168da27Sjohnlev terminate("%s: DWARF version 1 is not supported\n",
124c168da27Sjohnlev filename);
125c168da27Sjohnlev }
1267c478bd9Sstevel@tonic-gate
1277c478bd9Sstevel@tonic-gate if (!(source_types & SOURCE_C) && ignore_non_c) {
1287c478bd9Sstevel@tonic-gate debug(1, "Ignoring file %s not built from C sources\n",
1297c478bd9Sstevel@tonic-gate filename);
1307c478bd9Sstevel@tonic-gate exit(0);
1317c478bd9Sstevel@tonic-gate }
1327c478bd9Sstevel@tonic-gate
1337c478bd9Sstevel@tonic-gate rc = 0;
1347c478bd9Sstevel@tonic-gate } else {
1357c478bd9Sstevel@tonic-gate rc = 1;
1367c478bd9Sstevel@tonic-gate }
1377c478bd9Sstevel@tonic-gate
1387c478bd9Sstevel@tonic-gate (void) elf_end(elf);
1397c478bd9Sstevel@tonic-gate (void) close(fd);
1407c478bd9Sstevel@tonic-gate
1417c478bd9Sstevel@tonic-gate return (rc);
1427c478bd9Sstevel@tonic-gate }
1437c478bd9Sstevel@tonic-gate
1447c478bd9Sstevel@tonic-gate int
main(int argc,char ** argv)1457c478bd9Sstevel@tonic-gate main(int argc, char **argv)
1467c478bd9Sstevel@tonic-gate {
1477c478bd9Sstevel@tonic-gate tdata_t *filetd, *mstrtd;
1487c478bd9Sstevel@tonic-gate char *label = NULL;
1497c478bd9Sstevel@tonic-gate int verbose = 0;
1507c478bd9Sstevel@tonic-gate int ignore_non_c = 0;
1517c478bd9Sstevel@tonic-gate int c;
1527c478bd9Sstevel@tonic-gate
1537c478bd9Sstevel@tonic-gate sighold(SIGINT);
1547c478bd9Sstevel@tonic-gate sighold(SIGQUIT);
1557c478bd9Sstevel@tonic-gate sighold(SIGTERM);
1567c478bd9Sstevel@tonic-gate
1577c478bd9Sstevel@tonic-gate progname = basename(argv[0]);
1587c478bd9Sstevel@tonic-gate
1597c478bd9Sstevel@tonic-gate if (getenv("CTFCONVERT_DEBUG_LEVEL"))
1607c478bd9Sstevel@tonic-gate debug_level = atoi(getenv("CTFCONVERT_DEBUG_LEVEL"));
1617c478bd9Sstevel@tonic-gate if (getenv("CTFCONVERT_DEBUG_PARSE"))
1627c478bd9Sstevel@tonic-gate debug_parse = atoi(getenv("CTFCONVERT_DEBUG_PARSE"));
1637c478bd9Sstevel@tonic-gate
164495021bdSRichard Lowe while ((c = getopt(argc, argv, ":l:L:o:ivs")) != EOF) {
1657c478bd9Sstevel@tonic-gate switch (c) {
1667c478bd9Sstevel@tonic-gate case 'l':
1677c478bd9Sstevel@tonic-gate label = optarg;
1687c478bd9Sstevel@tonic-gate break;
1697c478bd9Sstevel@tonic-gate case 'L':
1707c478bd9Sstevel@tonic-gate if ((label = getenv(optarg)) == NULL)
1717c478bd9Sstevel@tonic-gate label = CTF_DEFAULT_LABEL;
1727c478bd9Sstevel@tonic-gate break;
1737c478bd9Sstevel@tonic-gate case 'o':
1747c478bd9Sstevel@tonic-gate outfile = optarg;
1757c478bd9Sstevel@tonic-gate break;
1767c478bd9Sstevel@tonic-gate case 's':
1777c478bd9Sstevel@tonic-gate dynsym = CTF_USE_DYNSYM;
1787c478bd9Sstevel@tonic-gate break;
1797c478bd9Sstevel@tonic-gate case 'i':
1807c478bd9Sstevel@tonic-gate ignore_non_c = 1;
1817c478bd9Sstevel@tonic-gate break;
1827c478bd9Sstevel@tonic-gate case 'v':
1837c478bd9Sstevel@tonic-gate verbose = 1;
1847c478bd9Sstevel@tonic-gate break;
1857c478bd9Sstevel@tonic-gate default:
1867c478bd9Sstevel@tonic-gate usage();
1877c478bd9Sstevel@tonic-gate exit(2);
1887c478bd9Sstevel@tonic-gate }
1897c478bd9Sstevel@tonic-gate }
1907c478bd9Sstevel@tonic-gate
1917c478bd9Sstevel@tonic-gate if (argc - optind != 1 || label == NULL) {
1927c478bd9Sstevel@tonic-gate usage();
1937c478bd9Sstevel@tonic-gate exit(2);
1947c478bd9Sstevel@tonic-gate }
1957c478bd9Sstevel@tonic-gate
1967c478bd9Sstevel@tonic-gate infile = argv[optind];
1977c478bd9Sstevel@tonic-gate if (access(infile, R_OK) != 0)
1987c478bd9Sstevel@tonic-gate terminate("Can't access %s", infile);
1997c478bd9Sstevel@tonic-gate
2007c478bd9Sstevel@tonic-gate /*
2017c478bd9Sstevel@tonic-gate * Upon receipt of a signal, we want to clean up and exit. Our
2027c478bd9Sstevel@tonic-gate * primary goal during cleanup is to restore the system to a state
2037c478bd9Sstevel@tonic-gate * such that a subsequent make will eventually cause this command to
2047c478bd9Sstevel@tonic-gate * be re-run. If we remove the input file (which we do if we get a
2057c478bd9Sstevel@tonic-gate * signal and the user didn't specify a separate output file), make
2067c478bd9Sstevel@tonic-gate * will need to rebuild the input file, and will then need to re-run
2077c478bd9Sstevel@tonic-gate * ctfconvert, which is what we want.
2087c478bd9Sstevel@tonic-gate */
2097c478bd9Sstevel@tonic-gate set_terminate_cleanup(terminate_cleanup);
2107c478bd9Sstevel@tonic-gate
2117c478bd9Sstevel@tonic-gate sigset(SIGINT, handle_sig);
2127c478bd9Sstevel@tonic-gate sigset(SIGQUIT, handle_sig);
2137c478bd9Sstevel@tonic-gate sigset(SIGTERM, handle_sig);
2147c478bd9Sstevel@tonic-gate
2157c478bd9Sstevel@tonic-gate filetd = tdata_new();
2167c478bd9Sstevel@tonic-gate
2177c478bd9Sstevel@tonic-gate if (!file_read(filetd, infile, ignore_non_c))
2187c478bd9Sstevel@tonic-gate terminate("%s doesn't have type data to convert\n", infile);
2197c478bd9Sstevel@tonic-gate
2207c478bd9Sstevel@tonic-gate if (verbose)
2217c478bd9Sstevel@tonic-gate iidesc_stats(filetd->td_iihash);
2227c478bd9Sstevel@tonic-gate
2237c478bd9Sstevel@tonic-gate mstrtd = tdata_new();
2247c478bd9Sstevel@tonic-gate merge_into_master(filetd, mstrtd, NULL, 1);
2257c478bd9Sstevel@tonic-gate
2267c478bd9Sstevel@tonic-gate tdata_label_add(mstrtd, label, CTF_LABEL_LASTIDX);
2277c478bd9Sstevel@tonic-gate
2287c478bd9Sstevel@tonic-gate /*
2297c478bd9Sstevel@tonic-gate * If the user supplied an output file that is different from the
2307c478bd9Sstevel@tonic-gate * input file, write directly to the output file. Otherwise, write
2317c478bd9Sstevel@tonic-gate * to a temporary file, and replace the input file when we're done.
2327c478bd9Sstevel@tonic-gate */
2337c478bd9Sstevel@tonic-gate if (outfile && strcmp(infile, outfile) != 0) {
234495021bdSRichard Lowe write_ctf(mstrtd, infile, outfile, dynsym);
2357c478bd9Sstevel@tonic-gate } else {
2367c478bd9Sstevel@tonic-gate char *tmpname = mktmpname(infile, ".ctf");
2377c478bd9Sstevel@tonic-gate
238495021bdSRichard Lowe write_ctf(mstrtd, infile, tmpname, dynsym);
2397c478bd9Sstevel@tonic-gate if (rename(tmpname, infile) != 0)
2407c478bd9Sstevel@tonic-gate terminate("Couldn't rename temp file %s", tmpname);
2417c478bd9Sstevel@tonic-gate free(tmpname);
2427c478bd9Sstevel@tonic-gate }
2437c478bd9Sstevel@tonic-gate
2447c478bd9Sstevel@tonic-gate return (0);
2457c478bd9Sstevel@tonic-gate }
246