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