1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * Given a file containing sections with stabs data, convert the stabs data to 31*0Sstevel@tonic-gate * CTF data, and replace the stabs sections with a CTF section. 32*0Sstevel@tonic-gate */ 33*0Sstevel@tonic-gate 34*0Sstevel@tonic-gate #include <stdio.h> 35*0Sstevel@tonic-gate #include <stdlib.h> 36*0Sstevel@tonic-gate #include <unistd.h> 37*0Sstevel@tonic-gate #include <signal.h> 38*0Sstevel@tonic-gate #include <string.h> 39*0Sstevel@tonic-gate #include <fcntl.h> 40*0Sstevel@tonic-gate #include <libgen.h> 41*0Sstevel@tonic-gate #include <errno.h> 42*0Sstevel@tonic-gate #include <assert.h> 43*0Sstevel@tonic-gate 44*0Sstevel@tonic-gate #include "ctftools.h" 45*0Sstevel@tonic-gate #include "memory.h" 46*0Sstevel@tonic-gate 47*0Sstevel@tonic-gate const char *progname; 48*0Sstevel@tonic-gate int debug_level = DEBUG_LEVEL; 49*0Sstevel@tonic-gate 50*0Sstevel@tonic-gate static const char *infile = NULL; 51*0Sstevel@tonic-gate static const char *outfile = NULL; 52*0Sstevel@tonic-gate static int dynsym; 53*0Sstevel@tonic-gate 54*0Sstevel@tonic-gate static void 55*0Sstevel@tonic-gate usage(void) 56*0Sstevel@tonic-gate { 57*0Sstevel@tonic-gate (void) fprintf(stderr, 58*0Sstevel@tonic-gate "Usage: %s [-gis] -l label | -L labelenv [-o outfile] object_file\n" 59*0Sstevel@tonic-gate "\n" 60*0Sstevel@tonic-gate " Note: if -L labelenv is specified and labelenv is not set in\n" 61*0Sstevel@tonic-gate " the environment, a default value is used.\n", 62*0Sstevel@tonic-gate progname); 63*0Sstevel@tonic-gate } 64*0Sstevel@tonic-gate 65*0Sstevel@tonic-gate static void 66*0Sstevel@tonic-gate terminate_cleanup(void) 67*0Sstevel@tonic-gate { 68*0Sstevel@tonic-gate if (!outfile) { 69*0Sstevel@tonic-gate fprintf(stderr, "Removing %s\n", infile); 70*0Sstevel@tonic-gate unlink(infile); 71*0Sstevel@tonic-gate } 72*0Sstevel@tonic-gate } 73*0Sstevel@tonic-gate 74*0Sstevel@tonic-gate static void 75*0Sstevel@tonic-gate handle_sig(int sig) 76*0Sstevel@tonic-gate { 77*0Sstevel@tonic-gate terminate("Caught signal %d - exiting\n", sig); 78*0Sstevel@tonic-gate } 79*0Sstevel@tonic-gate 80*0Sstevel@tonic-gate static int 81*0Sstevel@tonic-gate file_read(tdata_t *td, const char *filename, int ignore_non_c) 82*0Sstevel@tonic-gate { 83*0Sstevel@tonic-gate typedef int (*reader_f)(tdata_t *, Elf *, const char *); 84*0Sstevel@tonic-gate static const reader_f readers[] = { 85*0Sstevel@tonic-gate stabs_read, 86*0Sstevel@tonic-gate dw_read, 87*0Sstevel@tonic-gate NULL 88*0Sstevel@tonic-gate }; 89*0Sstevel@tonic-gate 90*0Sstevel@tonic-gate source_types_t source_types; 91*0Sstevel@tonic-gate Elf *elf; 92*0Sstevel@tonic-gate int i, rc, fd; 93*0Sstevel@tonic-gate 94*0Sstevel@tonic-gate if ((fd = open(filename, O_RDONLY)) < 0) 95*0Sstevel@tonic-gate terminate("failed to open %s", filename); 96*0Sstevel@tonic-gate 97*0Sstevel@tonic-gate (void) elf_version(EV_CURRENT); 98*0Sstevel@tonic-gate 99*0Sstevel@tonic-gate if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 100*0Sstevel@tonic-gate close(fd); 101*0Sstevel@tonic-gate terminate("failed to read %s: %s\n", filename, 102*0Sstevel@tonic-gate elf_errmsg(elf_errno())); 103*0Sstevel@tonic-gate } 104*0Sstevel@tonic-gate 105*0Sstevel@tonic-gate source_types = built_source_types(elf, filename); 106*0Sstevel@tonic-gate 107*0Sstevel@tonic-gate if ((source_types == SOURCE_NONE || (source_types & SOURCE_UNKNOWN)) && 108*0Sstevel@tonic-gate ignore_non_c) { 109*0Sstevel@tonic-gate debug(1, "Ignoring file %s from unknown sources\n", filename); 110*0Sstevel@tonic-gate exit(0); 111*0Sstevel@tonic-gate } 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate for (i = 0; readers[i] != NULL; i++) { 114*0Sstevel@tonic-gate if ((rc = readers[i](td, elf, filename)) == 0) 115*0Sstevel@tonic-gate break; 116*0Sstevel@tonic-gate 117*0Sstevel@tonic-gate assert(rc < 0 && errno == ENOENT); 118*0Sstevel@tonic-gate } 119*0Sstevel@tonic-gate 120*0Sstevel@tonic-gate if (readers[i] == NULL) { 121*0Sstevel@tonic-gate /* 122*0Sstevel@tonic-gate * None of the readers found compatible type data. 123*0Sstevel@tonic-gate */ 124*0Sstevel@tonic-gate 125*0Sstevel@tonic-gate if (findelfsecidx(elf, ".debug") >= 0) 126*0Sstevel@tonic-gate terminate("DWARF version 1 is not supported\n"); 127*0Sstevel@tonic-gate 128*0Sstevel@tonic-gate if (!(source_types & SOURCE_C) && ignore_non_c) { 129*0Sstevel@tonic-gate debug(1, "Ignoring file %s not built from C sources\n", 130*0Sstevel@tonic-gate filename); 131*0Sstevel@tonic-gate exit(0); 132*0Sstevel@tonic-gate } 133*0Sstevel@tonic-gate 134*0Sstevel@tonic-gate rc = 0; 135*0Sstevel@tonic-gate } else { 136*0Sstevel@tonic-gate rc = 1; 137*0Sstevel@tonic-gate } 138*0Sstevel@tonic-gate 139*0Sstevel@tonic-gate (void) elf_end(elf); 140*0Sstevel@tonic-gate (void) close(fd); 141*0Sstevel@tonic-gate 142*0Sstevel@tonic-gate return (rc); 143*0Sstevel@tonic-gate } 144*0Sstevel@tonic-gate 145*0Sstevel@tonic-gate int 146*0Sstevel@tonic-gate main(int argc, char **argv) 147*0Sstevel@tonic-gate { 148*0Sstevel@tonic-gate tdata_t *filetd, *mstrtd; 149*0Sstevel@tonic-gate char *label = NULL; 150*0Sstevel@tonic-gate int verbose = 0; 151*0Sstevel@tonic-gate int ignore_non_c = 0; 152*0Sstevel@tonic-gate int keep_stabs = 0; 153*0Sstevel@tonic-gate int c; 154*0Sstevel@tonic-gate 155*0Sstevel@tonic-gate sighold(SIGINT); 156*0Sstevel@tonic-gate sighold(SIGQUIT); 157*0Sstevel@tonic-gate sighold(SIGTERM); 158*0Sstevel@tonic-gate 159*0Sstevel@tonic-gate progname = basename(argv[0]); 160*0Sstevel@tonic-gate 161*0Sstevel@tonic-gate if (getenv("CTFCONVERT_DEBUG_LEVEL")) 162*0Sstevel@tonic-gate debug_level = atoi(getenv("CTFCONVERT_DEBUG_LEVEL")); 163*0Sstevel@tonic-gate if (getenv("CTFCONVERT_DEBUG_PARSE")) 164*0Sstevel@tonic-gate debug_parse = atoi(getenv("CTFCONVERT_DEBUG_PARSE")); 165*0Sstevel@tonic-gate 166*0Sstevel@tonic-gate while ((c = getopt(argc, argv, ":l:L:o:givs")) != EOF) { 167*0Sstevel@tonic-gate switch (c) { 168*0Sstevel@tonic-gate case 'l': 169*0Sstevel@tonic-gate label = optarg; 170*0Sstevel@tonic-gate break; 171*0Sstevel@tonic-gate case 'L': 172*0Sstevel@tonic-gate if ((label = getenv(optarg)) == NULL) 173*0Sstevel@tonic-gate label = CTF_DEFAULT_LABEL; 174*0Sstevel@tonic-gate break; 175*0Sstevel@tonic-gate case 'o': 176*0Sstevel@tonic-gate outfile = optarg; 177*0Sstevel@tonic-gate break; 178*0Sstevel@tonic-gate case 's': 179*0Sstevel@tonic-gate dynsym = CTF_USE_DYNSYM; 180*0Sstevel@tonic-gate break; 181*0Sstevel@tonic-gate case 'i': 182*0Sstevel@tonic-gate ignore_non_c = 1; 183*0Sstevel@tonic-gate break; 184*0Sstevel@tonic-gate case 'g': 185*0Sstevel@tonic-gate keep_stabs = CTF_KEEP_STABS; 186*0Sstevel@tonic-gate break; 187*0Sstevel@tonic-gate case 'v': 188*0Sstevel@tonic-gate verbose = 1; 189*0Sstevel@tonic-gate break; 190*0Sstevel@tonic-gate default: 191*0Sstevel@tonic-gate usage(); 192*0Sstevel@tonic-gate exit(2); 193*0Sstevel@tonic-gate } 194*0Sstevel@tonic-gate } 195*0Sstevel@tonic-gate 196*0Sstevel@tonic-gate if (getenv("STRIPSTABS_KEEP_STABS") != NULL) 197*0Sstevel@tonic-gate keep_stabs = CTF_KEEP_STABS; 198*0Sstevel@tonic-gate 199*0Sstevel@tonic-gate if (argc - optind != 1 || label == NULL) { 200*0Sstevel@tonic-gate usage(); 201*0Sstevel@tonic-gate exit(2); 202*0Sstevel@tonic-gate } 203*0Sstevel@tonic-gate 204*0Sstevel@tonic-gate infile = argv[optind]; 205*0Sstevel@tonic-gate if (access(infile, R_OK) != 0) 206*0Sstevel@tonic-gate terminate("Can't access %s", infile); 207*0Sstevel@tonic-gate 208*0Sstevel@tonic-gate /* 209*0Sstevel@tonic-gate * Upon receipt of a signal, we want to clean up and exit. Our 210*0Sstevel@tonic-gate * primary goal during cleanup is to restore the system to a state 211*0Sstevel@tonic-gate * such that a subsequent make will eventually cause this command to 212*0Sstevel@tonic-gate * be re-run. If we remove the input file (which we do if we get a 213*0Sstevel@tonic-gate * signal and the user didn't specify a separate output file), make 214*0Sstevel@tonic-gate * will need to rebuild the input file, and will then need to re-run 215*0Sstevel@tonic-gate * ctfconvert, which is what we want. 216*0Sstevel@tonic-gate */ 217*0Sstevel@tonic-gate set_terminate_cleanup(terminate_cleanup); 218*0Sstevel@tonic-gate 219*0Sstevel@tonic-gate sigset(SIGINT, handle_sig); 220*0Sstevel@tonic-gate sigset(SIGQUIT, handle_sig); 221*0Sstevel@tonic-gate sigset(SIGTERM, handle_sig); 222*0Sstevel@tonic-gate 223*0Sstevel@tonic-gate filetd = tdata_new(); 224*0Sstevel@tonic-gate 225*0Sstevel@tonic-gate if (!file_read(filetd, infile, ignore_non_c)) 226*0Sstevel@tonic-gate terminate("%s doesn't have type data to convert\n", infile); 227*0Sstevel@tonic-gate 228*0Sstevel@tonic-gate if (verbose) 229*0Sstevel@tonic-gate iidesc_stats(filetd->td_iihash); 230*0Sstevel@tonic-gate 231*0Sstevel@tonic-gate mstrtd = tdata_new(); 232*0Sstevel@tonic-gate merge_into_master(filetd, mstrtd, NULL, 1); 233*0Sstevel@tonic-gate 234*0Sstevel@tonic-gate tdata_label_add(mstrtd, label, CTF_LABEL_LASTIDX); 235*0Sstevel@tonic-gate 236*0Sstevel@tonic-gate /* 237*0Sstevel@tonic-gate * If the user supplied an output file that is different from the 238*0Sstevel@tonic-gate * input file, write directly to the output file. Otherwise, write 239*0Sstevel@tonic-gate * to a temporary file, and replace the input file when we're done. 240*0Sstevel@tonic-gate */ 241*0Sstevel@tonic-gate if (outfile && strcmp(infile, outfile) != 0) { 242*0Sstevel@tonic-gate write_ctf(mstrtd, infile, outfile, dynsym | keep_stabs); 243*0Sstevel@tonic-gate } else { 244*0Sstevel@tonic-gate char *tmpname = mktmpname(infile, ".ctf"); 245*0Sstevel@tonic-gate 246*0Sstevel@tonic-gate write_ctf(mstrtd, infile, tmpname, dynsym | keep_stabs); 247*0Sstevel@tonic-gate if (rename(tmpname, infile) != 0) 248*0Sstevel@tonic-gate terminate("Couldn't rename temp file %s", tmpname); 249*0Sstevel@tonic-gate free(tmpname); 250*0Sstevel@tonic-gate } 251*0Sstevel@tonic-gate 252*0Sstevel@tonic-gate return (0); 253*0Sstevel@tonic-gate } 254