Print this page
10816 ctf_dwarf_convert_type() relies on un-initialized id
10817 ctfconvert -i option is mis-handled
10818 Improve ctfconvert error messages
10819 ctfconvert should handle empty dies
10820 ctfconvert -i never converts
10821 bad free in ctf_dwarf_init_die
10815 shouldn't build gcore.c as part of kmdb
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/ctfconvert/ctfconvert.c
+++ new/usr/src/cmd/ctfconvert/ctfconvert.c
1 1 /*
2 2 * This file and its contents are supplied under the terms of the
↓ open down ↓ |
2 lines elided |
↑ open up ↑ |
3 3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 4 * You may only use this file in accordance with the terms of version
5 5 * 1.0 of the CDDL.
6 6 *
7 7 * A full copy of the text of the CDDL should have accompanied this
8 8 * source. A copy of the CDDL is also available via the Internet at
9 9 * http://www.illumos.org/license/CDDL.
10 10 */
11 11
12 12 /*
13 - * Copyright (c) 2015, Joyent, Inc.
13 + * Copyright (c) 2019, Joyent, Inc.
14 14 */
15 15
16 16 /*
17 17 * Create CTF from extant debugging information
18 18 */
19 19
20 20 #include <stdio.h>
21 21 #include <unistd.h>
22 22 #include <stdlib.h>
23 23 #include <stdarg.h>
24 24 #include <sys/types.h>
25 25 #include <sys/stat.h>
26 26 #include <fcntl.h>
27 27 #include <errno.h>
28 28 #include <libelf.h>
29 29 #include <libctf.h>
30 30 #include <string.h>
31 31 #include <libgen.h>
32 32 #include <limits.h>
33 33 #include <strings.h>
34 34 #include <sys/debug.h>
35 35
36 36 #define CTFCONVERT_OK 0
37 37 #define CTFCONVERT_FATAL 1
38 38 #define CTFCONVERT_USAGE 2
39 39
40 40 #define CTFCONVERT_DEFAULT_NTHREADS 4
41 41
42 42 #define CTFCONVERT_ALTEXEC "CTFCONVERT_ALTEXEC"
43 43
44 44 static char *ctfconvert_progname;
45 45
46 46 static void
47 47 ctfconvert_fatal(const char *fmt, ...)
48 48 {
49 49 va_list ap;
50 50
51 51 (void) fprintf(stderr, "%s: ", ctfconvert_progname);
52 52 va_start(ap, fmt);
53 53 (void) vfprintf(stderr, fmt, ap);
54 54 va_end(ap);
55 55
56 56 exit(CTFCONVERT_FATAL);
57 57 }
58 58
59 59
60 60 static void
61 61 ctfconvert_usage(const char *fmt, ...)
↓ open down ↓ |
38 lines elided |
↑ open up ↑ |
62 62 {
63 63 if (fmt != NULL) {
64 64 va_list ap;
65 65
66 66 (void) fprintf(stderr, "%s: ", ctfconvert_progname);
67 67 va_start(ap, fmt);
68 68 (void) vfprintf(stderr, fmt, ap);
69 69 va_end(ap);
70 70 }
71 71
72 - (void) fprintf(stderr, "Usage: %s [-is] [-j nthrs] [-l label | "
72 + (void) fprintf(stderr, "Usage: %s [-ims] [-j nthrs] [-l label | "
73 73 "-L labelenv] [-o outfile] input\n"
74 74 "\n"
75 75 "\t-i ignore files not built partially from C sources\n"
76 76 "\t-j use nthrs threads to perform the merge\n"
77 77 "\t-k keep around original input file on failure\n"
78 + "\t-m allow input to have missing debug info\n"
78 79 "\t-o copy input to outfile and add CTF\n"
79 80 "\t-l set output container's label to specified value\n"
80 81 "\t-L set output container's label to value from environment\n",
81 82 ctfconvert_progname);
82 83 }
83 84
84 85 /*
85 86 * This is a bit unfortunate. Traditionally we do type uniquification across all
86 87 * modules in the kernel, including ip and unix against genunix. However, when
87 88 * _MACHDEP is defined, then the cpu_t ends up having an additional member
88 89 * (cpu_m), thus changing the ability for us to uniquify against it. This in
89 90 * turn causes a lot of type sprawl, as there's a lot of things that end up
90 91 * referring to the cpu_t and it chains out from there.
91 92 *
92 93 * So, if we find that a cpu_t has been defined and it has a couple of useful
93 94 * sentinel members and it does *not* have the cpu_m member, then we will try
94 95 * and lookup or create a forward declaration to the machcpu, append it to the
95 96 * end, and update the file.
96 97 *
97 98 * This currently is only invoked if an undocumented option -X is passed. This
98 99 * value is private to illumos and it can be changed at any time inside of it,
99 100 * so if -X wants to be used for something, it should be. The ability to rely on
100 101 * -X for others is strictly not an interface in any way, shape, or form.
101 102 *
102 103 * The following struct contains most of the information that we care about and
103 104 * that we want to validate exists before we decide what to do.
104 105 */
105 106
106 107 typedef struct ctfconvert_fixup {
107 108 boolean_t cf_cyclic; /* Do we have a cpu_cyclic member */
108 109 boolean_t cf_mcpu; /* We have a cpu_m member */
109 110 boolean_t cf_lastpad; /* Is the pad member the last entry */
110 111 ulong_t cf_padoff; /* offset of the pad */
111 112 } ctfconvert_fixup_t;
112 113
113 114 /* ARGSUSED */
114 115 static int
115 116 ctfconvert_fixup_genunix_cb(const char *name, ctf_id_t tid, ulong_t off,
116 117 void *arg)
117 118 {
118 119 ctfconvert_fixup_t *cfp = arg;
119 120
120 121 cfp->cf_lastpad = B_FALSE;
121 122 if (strcmp(name, "cpu_cyclic") == 0) {
122 123 cfp->cf_cyclic = B_TRUE;
123 124 return (0);
124 125 }
125 126
126 127 if (strcmp(name, "cpu_m") == 0) {
127 128 cfp->cf_mcpu = B_TRUE;
128 129 return (0);
129 130 }
130 131
131 132 if (strcmp(name, "cpu_m_pad") == 0) {
132 133 cfp->cf_lastpad = B_TRUE;
133 134 cfp->cf_padoff = off;
134 135 return (0);
135 136 }
136 137
137 138 return (0);
138 139 }
139 140
140 141 static void
141 142 ctfconvert_fixup_genunix(ctf_file_t *fp)
142 143 {
143 144 ctf_id_t cpuid, mcpu;
144 145 ssize_t sz;
145 146 ctfconvert_fixup_t cf;
146 147 int model, ptrsz;
147 148
148 149 cpuid = ctf_lookup_by_name(fp, "struct cpu");
149 150 if (cpuid == CTF_ERR)
150 151 return;
151 152
152 153 if (ctf_type_kind(fp, cpuid) != CTF_K_STRUCT)
153 154 return;
154 155
155 156 if ((sz = ctf_type_size(fp, cpuid)) == CTF_ERR)
156 157 return;
157 158
158 159 model = ctf_getmodel(fp);
159 160 VERIFY(model == CTF_MODEL_ILP32 || model == CTF_MODEL_LP64);
160 161 ptrsz = model == CTF_MODEL_ILP32 ? 4 : 8;
161 162
162 163 bzero(&cf, sizeof (ctfconvert_fixup_t));
163 164 if (ctf_member_iter(fp, cpuid, ctfconvert_fixup_genunix_cb, &cf) ==
164 165 CTF_ERR)
165 166 return;
166 167
167 168 /*
168 169 * Finally, we want to verify that the cpu_m is actually the last member
169 170 * that we have here.
170 171 */
171 172 if (cf.cf_cyclic == B_FALSE || cf.cf_mcpu == B_TRUE ||
172 173 cf.cf_lastpad == B_FALSE) {
173 174 return;
174 175 }
175 176
176 177 if (cf.cf_padoff + ptrsz * NBBY != sz * NBBY) {
177 178 return;
178 179 }
179 180
180 181 /*
181 182 * Okay, we're going to do this, try to find a struct machcpu. We either
182 183 * want a forward or a struct. If we find something else, error. If we
183 184 * find nothing, add a forward and then add the member.
184 185 */
185 186 mcpu = ctf_lookup_by_name(fp, "struct machcpu");
186 187 if (mcpu == CTF_ERR) {
187 188 mcpu = ctf_add_forward(fp, CTF_ADD_NONROOT, "machcpu",
188 189 CTF_K_STRUCT);
189 190 if (mcpu == CTF_ERR) {
190 191 ctfconvert_fatal("failed to add 'struct machcpu' "
191 192 "forward: %s", ctf_errmsg(ctf_errno(fp)));
192 193 }
193 194 } else {
194 195 int kind;
195 196 if ((kind = ctf_type_kind(fp, mcpu)) == CTF_ERR) {
196 197 ctfconvert_fatal("failed to get the type kind for "
197 198 "the struct machcpu: %s",
198 199 ctf_errmsg(ctf_errno(fp)));
199 200 }
200 201
201 202 if (kind != CTF_K_STRUCT && kind != CTF_K_FORWARD)
202 203 ctfconvert_fatal("encountered a struct machcpu of the "
203 204 "wrong type, found type kind %d\n", kind);
204 205 }
205 206
206 207 if (ctf_update(fp) == CTF_ERR) {
207 208 ctfconvert_fatal("failed to update output file: %s\n",
208 209 ctf_errmsg(ctf_errno(fp)));
209 210 }
210 211
211 212 if (ctf_add_member(fp, cpuid, "cpu_m", mcpu, sz * NBBY) == CTF_ERR) {
212 213 ctfconvert_fatal("failed to add the m_cpu member: %s\n",
213 214 ctf_errmsg(ctf_errno(fp)));
214 215 }
215 216
216 217 if (ctf_update(fp) == CTF_ERR) {
217 218 ctfconvert_fatal("failed to update output file: %s\n",
218 219 ctf_errmsg(ctf_errno(fp)));
219 220 }
220 221
221 222 VERIFY(ctf_type_size(fp, cpuid) == sz);
222 223 }
223 224
224 225 static void
225 226 ctfconvert_altexec(char **argv)
226 227 {
227 228 const char *alt;
228 229 char *altexec;
229 230
230 231 alt = getenv(CTFCONVERT_ALTEXEC);
231 232 if (alt == NULL || *alt == '\0')
232 233 return;
233 234
234 235 altexec = strdup(alt);
235 236 if (altexec == NULL)
236 237 ctfconvert_fatal("failed to allocate memory for altexec\n");
237 238 if (unsetenv(CTFCONVERT_ALTEXEC) != 0)
238 239 ctfconvert_fatal("failed to unset %s from environment: %s\n",
239 240 CTFCONVERT_ALTEXEC, strerror(errno));
240 241
241 242 (void) execv(altexec, argv);
242 243 ctfconvert_fatal("failed to execute alternate program %s: %s",
243 244 altexec, strerror(errno));
244 245 }
245 246
246 247 int
247 248 main(int argc, char *argv[])
248 249 {
249 250 int c, ifd, err;
250 251 boolean_t keep = B_FALSE;
251 252 uint_t flags = 0;
↓ open down ↓ |
164 lines elided |
↑ open up ↑ |
252 253 uint_t nthreads = CTFCONVERT_DEFAULT_NTHREADS;
253 254 const char *outfile = NULL;
254 255 const char *label = NULL;
255 256 const char *infile = NULL;
256 257 char *tmpfile;
257 258 ctf_file_t *ofp;
258 259 long argj;
259 260 char *eptr;
260 261 char buf[4096];
261 262 boolean_t optx = B_FALSE;
263 + boolean_t ignore_non_c = B_FALSE;
262 264
263 265 ctfconvert_progname = basename(argv[0]);
264 266
265 267 ctfconvert_altexec(argv);
266 268
267 - while ((c = getopt(argc, argv, ":j:kl:L:o:iX")) != -1) {
269 + while ((c = getopt(argc, argv, ":ij:kl:L:mo:X")) != -1) {
268 270 switch (c) {
269 - case 'k':
270 - keep = B_TRUE;
271 + case 'i':
272 + ignore_non_c = B_TRUE;
271 273 break;
272 - case 'l':
273 - label = optarg;
274 - break;
275 - case 'L':
276 - label = getenv(optarg);
277 - break;
278 274 case 'j':
279 275 errno = 0;
280 276 argj = strtol(optarg, &eptr, 10);
281 277 if (errno != 0 || argj == LONG_MAX ||
282 278 argj > 1024 || *eptr != '\0') {
283 279 ctfconvert_fatal("invalid argument for -j: "
284 280 "%s\n", optarg);
285 281 }
286 282 nthreads = (uint_t)argj;
287 283 break;
284 + case 'k':
285 + keep = B_TRUE;
286 + break;
287 + case 'l':
288 + label = optarg;
289 + break;
290 + case 'L':
291 + label = getenv(optarg);
292 + break;
293 + case 'm':
294 + flags |= CTF_ALLOW_MISSING_DEBUG;
295 + break;
288 296 case 'o':
289 297 outfile = optarg;
290 298 break;
291 - case 'i':
292 - flags |= CTF_CONVERT_F_IGNNONC;
293 - break;
294 299 case 'X':
295 300 optx = B_TRUE;
296 301 break;
297 302 case ':':
298 303 ctfconvert_usage("Option -%c requires an operand\n",
299 304 optopt);
300 305 return (CTFCONVERT_USAGE);
301 306 case '?':
302 307 ctfconvert_usage("Unknown option: -%c\n", optopt);
303 308 return (CTFCONVERT_USAGE);
304 309 }
305 310 }
306 311
307 312 argv += optind;
308 313 argc -= optind;
309 314
310 - if (argc < 1) {
311 - ctfconvert_usage("Missing required input file\n");
315 + if (argc != 1) {
316 + ctfconvert_usage("Exactly one input file is required\n");
312 317 return (CTFCONVERT_USAGE);
313 318 }
314 319 infile = argv[0];
315 320
316 321 if (elf_version(EV_CURRENT) == EV_NONE)
317 322 ctfconvert_fatal("failed to initialize libelf: library is "
318 323 "out of date\n");
319 324
320 325 ifd = open(infile, O_RDONLY);
321 326 if (ifd < 0) {
322 327 ctfconvert_fatal("failed to open input file %s: %s\n", infile,
323 328 strerror(errno));
324 329 }
325 330
326 331 /*
↓ open down ↓ |
5 lines elided |
↑ open up ↑ |
327 332 * By default we remove the input file on failure unless we've been
328 333 * given an output file or -k has been specified.
329 334 */
330 335 if (outfile != NULL && strcmp(infile, outfile) != 0)
331 336 keep = B_TRUE;
332 337
333 338 ofp = ctf_fdconvert(ifd, label, nthreads, flags, &err, buf,
334 339 sizeof (buf));
335 340 if (ofp == NULL) {
336 341 /*
337 - * -i says that we shouldn't concern ourselves with source files
338 - * that weren't built from C source code in part. Because this
339 - * has been traditionally used across all of illumos, we still
340 - * honor it.
342 + * Normally, ctfconvert requires that its input file has at
343 + * least one C-source compilation unit, and that every C-source
344 + * compilation unit has DWARF. This is to avoid accidentally
345 + * leaving out useful CTF.
346 + *
347 + * However, for the benefit of intransigent build environments,
348 + * the -i and -m options can be used to relax this.
341 349 */
342 - if ((flags & CTF_CONVERT_F_IGNNONC) != 0 &&
343 - err == ECTF_CONVNOCSRC) {
350 + if (err == ECTF_CONVNOCSRC && ignore_non_c) {
344 351 exit(CTFCONVERT_OK);
345 352 }
353 +
354 + if (err == ECTF_CONVNODEBUG &&
355 + (flags & CTF_ALLOW_MISSING_DEBUG) != 0) {
356 + exit(CTFCONVERT_OK);
357 + }
358 +
346 359 if (keep == B_FALSE)
347 360 (void) unlink(infile);
348 - ctfconvert_fatal("CTF conversion failed: %s\n",
349 - err == ECTF_CONVBKERR ? buf : ctf_errmsg(err));
361 +
362 + if (err == ECTF_CONVBKERR || err == ECTF_CONVNODEBUG) {
363 + ctfconvert_fatal("%s", buf);
364 + } else {
365 + ctfconvert_fatal("CTF conversion failed: %s\n",
366 + ctf_errmsg(err));
367 + }
350 368 }
351 369
352 370 if (optx == B_TRUE)
353 371 ctfconvert_fixup_genunix(ofp);
354 372
355 373 tmpfile = NULL;
356 374 if (outfile == NULL || strcmp(infile, outfile) == 0) {
357 375 if (asprintf(&tmpfile, "%s.ctf", infile) == -1) {
358 376 if (keep == B_FALSE)
359 377 (void) unlink(infile);
360 378 ctfconvert_fatal("failed to allocate memory for "
361 379 "temporary file: %s\n", strerror(errno));
362 380 }
363 381 outfile = tmpfile;
364 382 }
365 383 err = ctf_elfwrite(ofp, infile, outfile, CTF_ELFWRITE_F_COMPRESS);
366 384 if (err == CTF_ERR) {
367 385 (void) unlink(outfile);
368 386 if (keep == B_FALSE)
369 387 (void) unlink(infile);
370 388 ctfconvert_fatal("failed to write CTF section to output file: "
371 389 "%s", ctf_errmsg(ctf_errno(ofp)));
372 390 }
373 391 ctf_close(ofp);
374 392
375 393 if (tmpfile != NULL) {
376 394 if (rename(tmpfile, infile) != 0) {
377 395 int e = errno;
378 396 (void) unlink(outfile);
379 397 if (keep == B_FALSE)
380 398 (void) unlink(infile);
381 399 ctfconvert_fatal("failed to rename temporary file: "
382 400 "%s\n", strerror(e));
383 401 }
384 402 }
385 403 free(tmpfile);
386 404
387 405 return (CTFCONVERT_OK);
388 406 }
↓ open down ↓ |
29 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX