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