ctfconvert.c revision 1.2 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.1 darran #include <stdio.h>
34 1.1 darran #include <stdlib.h>
35 1.1 darran #include <unistd.h>
36 1.1 darran #include <signal.h>
37 1.1 darran #include <string.h>
38 1.1 darran #include <fcntl.h>
39 1.1 darran #include <libgen.h>
40 1.1 darran #include <errno.h>
41 1.1 darran #include <assert.h>
42 1.1 darran
43 1.1 darran #include "ctftools.h"
44 1.1 darran #include "memory.h"
45 1.1 darran
46 1.1 darran const char *progname;
47 1.1 darran int debug_level = DEBUG_LEVEL;
48 1.1 darran
49 1.2 darran static char *infile = NULL;
50 1.1 darran static const char *outfile = NULL;
51 1.1 darran static int dynsym;
52 1.1 darran
53 1.1 darran static void
54 1.1 darran usage(void)
55 1.1 darran {
56 1.1 darran (void) fprintf(stderr,
57 1.1 darran "Usage: %s [-gis] -l label | -L labelenv [-o outfile] object_file\n"
58 1.1 darran "\n"
59 1.1 darran " Note: if -L labelenv is specified and labelenv is not set in\n"
60 1.1 darran " the environment, a default value is used.\n",
61 1.1 darran progname);
62 1.1 darran }
63 1.1 darran
64 1.1 darran static void
65 1.1 darran terminate_cleanup(void)
66 1.1 darran {
67 1.2 darran #if !defined(__FreeBSD__)
68 1.1 darran if (!outfile) {
69 1.1 darran fprintf(stderr, "Removing %s\n", infile);
70 1.1 darran unlink(infile);
71 1.1 darran }
72 1.2 darran #endif
73 1.1 darran }
74 1.1 darran
75 1.1 darran static void
76 1.1 darran handle_sig(int sig)
77 1.1 darran {
78 1.1 darran terminate("Caught signal %d - exiting\n", sig);
79 1.1 darran }
80 1.1 darran
81 1.1 darran static int
82 1.2 darran file_read(tdata_t *td, char *filename, int ignore_non_c)
83 1.1 darran {
84 1.2 darran typedef int (*reader_f)(tdata_t *, Elf *, char *);
85 1.2 darran static reader_f readers[] = {
86 1.1 darran stabs_read,
87 1.1 darran dw_read,
88 1.1 darran NULL
89 1.1 darran };
90 1.1 darran
91 1.1 darran source_types_t source_types;
92 1.1 darran Elf *elf;
93 1.1 darran int i, rc, fd;
94 1.1 darran
95 1.1 darran if ((fd = open(filename, O_RDONLY)) < 0)
96 1.1 darran terminate("failed to open %s", filename);
97 1.1 darran
98 1.1 darran (void) elf_version(EV_CURRENT);
99 1.1 darran
100 1.1 darran if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
101 1.1 darran close(fd);
102 1.1 darran terminate("failed to read %s: %s\n", filename,
103 1.1 darran elf_errmsg(-1));
104 1.1 darran }
105 1.1 darran
106 1.1 darran source_types = built_source_types(elf, filename);
107 1.1 darran
108 1.1 darran if ((source_types == SOURCE_NONE || (source_types & SOURCE_UNKNOWN)) &&
109 1.1 darran ignore_non_c) {
110 1.1 darran debug(1, "Ignoring file %s from unknown sources\n", filename);
111 1.1 darran exit(0);
112 1.1 darran }
113 1.1 darran
114 1.1 darran for (i = 0; readers[i] != NULL; i++) {
115 1.1 darran if ((rc = readers[i](td, elf, filename)) == 0)
116 1.1 darran break;
117 1.1 darran
118 1.1 darran assert(rc < 0 && errno == ENOENT);
119 1.1 darran }
120 1.1 darran
121 1.1 darran if (readers[i] == NULL) {
122 1.1 darran /*
123 1.1 darran * None of the readers found compatible type data.
124 1.1 darran */
125 1.1 darran
126 1.1 darran if (findelfsecidx(elf, filename, ".debug") >= 0) {
127 1.1 darran terminate("%s: DWARF version 1 is not supported\n",
128 1.1 darran filename);
129 1.1 darran }
130 1.1 darran
131 1.1 darran if (!(source_types & SOURCE_C) && ignore_non_c) {
132 1.1 darran debug(1, "Ignoring file %s not built from C sources\n",
133 1.1 darran filename);
134 1.1 darran exit(0);
135 1.1 darran }
136 1.1 darran
137 1.1 darran rc = 0;
138 1.1 darran } else {
139 1.1 darran rc = 1;
140 1.1 darran }
141 1.1 darran
142 1.1 darran (void) elf_end(elf);
143 1.1 darran (void) close(fd);
144 1.1 darran
145 1.1 darran return (rc);
146 1.1 darran }
147 1.1 darran
148 1.1 darran int
149 1.1 darran main(int argc, char **argv)
150 1.1 darran {
151 1.1 darran tdata_t *filetd, *mstrtd;
152 1.2 darran const char *label = NULL;
153 1.1 darran int verbose = 0;
154 1.1 darran int ignore_non_c = 0;
155 1.1 darran int keep_stabs = 0;
156 1.1 darran int c;
157 1.1 darran
158 1.2 darran #if defined(sun)
159 1.1 darran sighold(SIGINT);
160 1.1 darran sighold(SIGQUIT);
161 1.1 darran sighold(SIGTERM);
162 1.2 darran #endif
163 1.1 darran
164 1.1 darran progname = basename(argv[0]);
165 1.1 darran
166 1.1 darran if (getenv("CTFCONVERT_DEBUG_LEVEL"))
167 1.1 darran debug_level = atoi(getenv("CTFCONVERT_DEBUG_LEVEL"));
168 1.1 darran if (getenv("CTFCONVERT_DEBUG_PARSE"))
169 1.1 darran debug_parse = atoi(getenv("CTFCONVERT_DEBUG_PARSE"));
170 1.1 darran
171 1.1 darran while ((c = getopt(argc, argv, ":l:L:o:givs")) != EOF) {
172 1.1 darran switch (c) {
173 1.1 darran case 'l':
174 1.1 darran label = optarg;
175 1.1 darran break;
176 1.1 darran case 'L':
177 1.1 darran if ((label = getenv(optarg)) == NULL)
178 1.1 darran label = CTF_DEFAULT_LABEL;
179 1.1 darran break;
180 1.1 darran case 'o':
181 1.1 darran outfile = optarg;
182 1.1 darran break;
183 1.1 darran case 's':
184 1.1 darran dynsym = CTF_USE_DYNSYM;
185 1.1 darran break;
186 1.1 darran case 'i':
187 1.1 darran ignore_non_c = 1;
188 1.1 darran break;
189 1.1 darran case 'g':
190 1.1 darran keep_stabs = CTF_KEEP_STABS;
191 1.1 darran break;
192 1.1 darran case 'v':
193 1.1 darran verbose = 1;
194 1.1 darran break;
195 1.1 darran default:
196 1.1 darran usage();
197 1.1 darran exit(2);
198 1.1 darran }
199 1.1 darran }
200 1.1 darran
201 1.1 darran if (getenv("STRIPSTABS_KEEP_STABS") != NULL)
202 1.1 darran keep_stabs = CTF_KEEP_STABS;
203 1.1 darran
204 1.1 darran if (argc - optind != 1 || label == NULL) {
205 1.1 darran usage();
206 1.1 darran exit(2);
207 1.1 darran }
208 1.1 darran
209 1.1 darran infile = argv[optind];
210 1.1 darran if (access(infile, R_OK) != 0)
211 1.1 darran terminate("Can't access %s", infile);
212 1.1 darran
213 1.1 darran /*
214 1.1 darran * Upon receipt of a signal, we want to clean up and exit. Our
215 1.1 darran * primary goal during cleanup is to restore the system to a state
216 1.1 darran * such that a subsequent make will eventually cause this command to
217 1.1 darran * be re-run. If we remove the input file (which we do if we get a
218 1.1 darran * signal and the user didn't specify a separate output file), make
219 1.1 darran * will need to rebuild the input file, and will then need to re-run
220 1.1 darran * ctfconvert, which is what we want.
221 1.1 darran */
222 1.1 darran set_terminate_cleanup(terminate_cleanup);
223 1.1 darran
224 1.2 darran #if defined(sun)
225 1.1 darran sigset(SIGINT, handle_sig);
226 1.1 darran sigset(SIGQUIT, handle_sig);
227 1.1 darran sigset(SIGTERM, handle_sig);
228 1.2 darran #else
229 1.2 darran signal(SIGINT, handle_sig);
230 1.2 darran signal(SIGQUIT, handle_sig);
231 1.2 darran signal(SIGTERM, handle_sig);
232 1.2 darran #endif
233 1.1 darran
234 1.1 darran filetd = tdata_new();
235 1.1 darran
236 1.1 darran if (!file_read(filetd, infile, ignore_non_c))
237 1.1 darran terminate("%s doesn't have type data to convert\n", infile);
238 1.1 darran
239 1.1 darran if (verbose)
240 1.1 darran iidesc_stats(filetd->td_iihash);
241 1.1 darran
242 1.1 darran mstrtd = tdata_new();
243 1.1 darran merge_into_master(filetd, mstrtd, NULL, 1);
244 1.1 darran
245 1.1 darran tdata_label_add(mstrtd, label, CTF_LABEL_LASTIDX);
246 1.1 darran
247 1.1 darran /*
248 1.1 darran * If the user supplied an output file that is different from the
249 1.1 darran * input file, write directly to the output file. Otherwise, write
250 1.1 darran * to a temporary file, and replace the input file when we're done.
251 1.1 darran */
252 1.1 darran if (outfile && strcmp(infile, outfile) != 0) {
253 1.1 darran write_ctf(mstrtd, infile, outfile, dynsym | keep_stabs);
254 1.1 darran } else {
255 1.1 darran char *tmpname = mktmpname(infile, ".ctf");
256 1.1 darran write_ctf(mstrtd, infile, tmpname, dynsym | keep_stabs);
257 1.1 darran if (rename(tmpname, infile) != 0)
258 1.1 darran terminate("Couldn't rename temp file %s", tmpname);
259 1.1 darran free(tmpname);
260 1.1 darran }
261 1.1 darran
262 1.1 darran return (0);
263 1.1 darran }
264