Deleted Added
full compact
main.c (148801) main.c (149954)
1/*
2 * Copyright (c) 2004 Marcel Moolenaar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
1/*
2 * Copyright (c) 2004 Marcel Moolenaar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/gnu/usr.bin/gdb/kgdb/main.c 148801 2005-08-06 19:07:07Z marcel $");
28__FBSDID("$FreeBSD: head/gnu/usr.bin/gdb/kgdb/main.c 149954 2005-09-10 18:25:53Z marcel $");
29
30#include <sys/param.h>
31#include <sys/stat.h>
32#include <sys/types.h>
33#include <sys/ioctl.h>
34#include <sys/resource.h>
35#include <sys/select.h>
36#include <sys/time.h>
37#include <sys/wait.h>
38#include <errno.h>
39#include <err.h>
40#include <fcntl.h>
41#include <inttypes.h>
42#include <kvm.h>
43#include <limits.h>
44#include <paths.h>
45#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48#include <unistd.h>
49
50/* libgdb stuff. */
51#include <defs.h>
52#include <frame.h>
29
30#include <sys/param.h>
31#include <sys/stat.h>
32#include <sys/types.h>
33#include <sys/ioctl.h>
34#include <sys/resource.h>
35#include <sys/select.h>
36#include <sys/time.h>
37#include <sys/wait.h>
38#include <errno.h>
39#include <err.h>
40#include <fcntl.h>
41#include <inttypes.h>
42#include <kvm.h>
43#include <limits.h>
44#include <paths.h>
45#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48#include <unistd.h>
49
50/* libgdb stuff. */
51#include <defs.h>
52#include <frame.h>
53#include <frame-unwind.h>
53#include <inferior.h>
54#include <interps.h>
55#include <cli-out.h>
56#include <main.h>
57#include <target.h>
58#include <top.h>
59#include <bfd.h>
60#include <gdbcore.h>
61
62extern void (*init_ui_hook)(char *);
63
54#include <inferior.h>
55#include <interps.h>
56#include <cli-out.h>
57#include <main.h>
58#include <target.h>
59#include <top.h>
60#include <bfd.h>
61#include <gdbcore.h>
62
63extern void (*init_ui_hook)(char *);
64
65extern frame_unwind_sniffer_ftype *kgdb_sniffer_kluge;
66
64extern void symbol_file_add_main (char *args, int from_tty);
65
66#include "kgdb.h"
67
68kvm_t *kvm;
69static char kvm_err[_POSIX2_LINE_MAX];
70
71static int dumpnr;
72static int verbose;
73
74static char crashdir[PATH_MAX];
75static char *kernel;
76static char *remote;
77static char *vmcore;
78
79static void (*kgdb_new_objfile_chain)(struct objfile * objfile);
80
81static void
82kgdb_atexit(void)
83{
84 if (kvm != NULL)
85 kvm_close(kvm);
86}
87
88static void
89usage(void)
90{
91
92 fprintf(stderr,
93 "usage: %s [-afqv] [-d crashdir] [-c core | -n dumpnr | -r device]\n"
94 "\t[kernel [core]]\n", getprogname());
95 exit(1);
96}
97
98static void
99kernel_from_dumpnr(int nr)
100{
101 char path[PATH_MAX];
102 FILE *info;
103 char *s;
104 struct stat st;
105 int l;
106
107 /*
108 * If there's a kernel image right here in the crash directory, then
109 * use it. The kernel image is either called kernel.<nr> or is in a
110 * subdirectory kernel.<nr> and called kernel. The latter allows us
111 * to collect the modules in the same place.
112 */
113 snprintf(path, sizeof(path), "%s/kernel.%d", crashdir, nr);
114 if (stat(path, &st) == 0) {
115 if (S_ISREG(st.st_mode)) {
116 kernel = strdup(path);
117 return;
118 }
119 if (S_ISDIR(st.st_mode)) {
120 snprintf(path, sizeof(path), "%s/kernel.%d/kernel",
121 crashdir, nr);
122 if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) {
123 kernel = strdup(path);
124 return;
125 }
126 }
127 }
128
129 /*
130 * No kernel image here. Parse the dump header. The kernel object
131 * directory can be found there and we probably have the kernel
132 * image still in it. The object directory may also have a kernel
133 * with debugging info (called kernel.debug). If we have a debug
134 * kernel, use it.
135 */
136 snprintf(path, sizeof(path), "%s/info.%d", crashdir, nr);
137 info = fopen(path, "r");
138 if (info == NULL) {
139 warn(path);
140 return;
141 }
142 while (fgets(path, sizeof(path), info) != NULL) {
143 l = strlen(path);
144 if (l > 0 && path[l - 1] == '\n')
145 path[--l] = '\0';
146 if (strncmp(path, " ", 4) == 0) {
147 s = strchr(path, ':');
148 s = (s == NULL) ? path + 4 : s + 1;
149 l = snprintf(path, sizeof(path), "%s/kernel.debug", s);
150 if (stat(path, &st) == -1 || !S_ISREG(st.st_mode)) {
151 path[l - 6] = '\0';
152 if (stat(path, &st) == -1 ||
153 !S_ISREG(st.st_mode))
154 break;
155 }
156 kernel = strdup(path);
157 break;
158 }
159 }
160 fclose(info);
161}
162
163static void
164kgdb_new_objfile(struct objfile *objfile)
165{
166#if 0
167 printf("XXX: %s(%p)\n", __func__, objfile);
168 if (objfile != NULL) {
169 goto out;
170 }
171
172out:
173#endif
174 if (kgdb_new_objfile_chain != NULL)
175 kgdb_new_objfile_chain(objfile);
176}
177
178static CORE_ADDR
179kgdb_parse(const char *exp)
180{
181 struct cleanup *old_chain;
182 struct expression *expr;
183 struct value *val;
184 char *s;
185 CORE_ADDR n;
186
187 s = strdup(exp);
188 old_chain = make_cleanup(free_current_contents, &expr);
189 expr = parse_expression(s);
190 val = (expr != NULL) ? evaluate_expression(expr) : NULL;
191 n = (val != NULL) ? value_as_address(val) : 0;
192 do_cleanups(old_chain);
193 free(s);
194 return (n);
195}
196
197static void
198kgdb_init_target(void)
199{
200 CORE_ADDR bufp;
201 bfd *kern_bfd;
202 int size, rseq, wseq;
203 int kern_desc;
204 char c;
205
206 kern_desc = open(kernel, O_RDONLY);
207 if (kern_desc == -1)
208 errx(1, "couldn't open a kernel image");
209
210 kern_bfd = bfd_fdopenr(kernel, gnutarget, kern_desc);
211 if (kern_bfd == NULL) {
212 close(kern_desc);
213 errx(1, "\"%s\": can't open to probe ABI: %s.", kernel,
214 bfd_errmsg (bfd_get_error ()));
215 }
216 bfd_set_cacheable(kern_bfd, 1);
217
218 if (!bfd_check_format (kern_bfd, bfd_object)) {
219 bfd_close(kern_bfd);
220 errx(1, "\"%s\": not in executable format: %s", kernel,
221 bfd_errmsg(bfd_get_error()));
222 }
223
224 set_gdbarch_from_file (kern_bfd);
225 bfd_close(kern_bfd);
226
227 symbol_file_add_main (kernel, 0);
228 if (remote)
229 push_remote_target (remote, 0);
230 else
231 kgdb_target();
232
233 /*
234 * Display the unread portion of the message buffer. This gives the
235 * user a some initial data to work from.
236 */
237 bufp = kgdb_parse("msgbufp->msg_ptr");
238 size = (int)kgdb_parse("msgbufp->msg_size");
239 rseq = (int)kgdb_parse("msgbufp->msg_rseq");
240 wseq = (int)kgdb_parse("msgbufp->msg_wseq");
241 if (bufp == 0 || size == 0 || rseq == wseq)
242 return;
243
244 printf("\nUnread portion of the kernel message buffer:\n");
245 while (rseq < wseq) {
246 read_memory(bufp + rseq, &c, 1);
247 putchar(c);
248 rseq++;
249 if (rseq == size)
250 rseq = 0;
251 }
252 if (c != '\n')
253 putchar('\n');
254 putchar('\n');
255}
256
257static void
258kgdb_interp_command_loop(void *data)
259{
260 static int once = 0;
261
262 if (!once) {
263 once = 1;
264 kgdb_init_target();
265 print_stack_frame(get_selected_frame(),
266 frame_relative_level(get_selected_frame()), 1);
267 }
268 command_loop();
269}
270
271static void
272kgdb_init(char *argv0 __unused)
273{
274 static struct interp_procs procs = {
275 NULL,
276 NULL,
277 NULL,
278 NULL,
279 NULL,
280 kgdb_interp_command_loop
281 };
282 struct interp *kgdb;
283 kgdb = interp_new("kgdb", NULL, cli_out_new(gdb_stdout), &procs);
284 interp_add(kgdb);
285
286 set_prompt("(kgdb) ");
287 kgdb_new_objfile_chain = target_new_objfile_hook;
288 target_new_objfile_hook = kgdb_new_objfile;
289}
290
291int
292main(int argc, char *argv[])
293{
294 char path[PATH_MAX];
295 struct stat st;
296 struct captured_main_args args;
297 char *s;
298 int a, ch, quiet;
299
300 dumpnr = -1;
301
302 strlcpy(crashdir, "/var/crash", sizeof(crashdir));
303 s = getenv("KGDB_CRASH_DIR");
304 if (s != NULL)
305 strlcpy(crashdir, s, sizeof(crashdir));
306
307 /* Convert long options into short options. */
308 for (a = 1; a < argc; a++) {
309 s = argv[a];
310 if (s[0] == '-') {
311 s++;
312 /* Long options take either 1 or 2 dashes. */
313 if (s[0] == '-')
314 s++;
315 if (strcmp(s, "quiet") == 0)
316 argv[a] = "-q";
317 else if (strcmp(s, "fullname") == 0)
318 argv[a] = "-f";
319 }
320 }
321
322 quiet = 0;
323
324 while ((ch = getopt(argc, argv, "ac:d:fn:qr:v")) != -1) {
325 switch (ch) {
326 case 'a':
327 annotation_level++;
328 break;
329 case 'c': /* use given core file. */
330 if (vmcore != NULL) {
331 warnx("option %c: can only be specified once",
332 optopt);
333 usage();
334 /* NOTREACHED */
335 }
336 vmcore = strdup(optarg);
337 break;
338 case 'd': /* lookup dumps in given directory. */
339 strlcpy(crashdir, optarg, sizeof(crashdir));
340 break;
341 case 'f':
342 annotation_level = 1;
343 break;
344 case 'n': /* use dump with given number. */
345 dumpnr = strtol(optarg, &s, 0);
346 if (dumpnr < 0 || *s != '\0') {
347 warnx("option %c: invalid kernel dump number",
348 optopt);
349 usage();
350 /* NOTREACHED */
351 }
352 break;
353 case 'q':
354 quiet = 1;
355 break;
356 case 'r': /* use given device for remote session. */
357 if (remote != NULL) {
358 warnx("option %c: can only be specified once",
359 optopt);
360 usage();
361 /* NOTREACHED */
362 }
363 remote = strdup(optarg);
364 break;
365 case 'v': /* increase verbosity. */
366 verbose++;
367 break;
368 case '?':
369 default:
370 usage();
371 }
372 }
373
374 if (((vmcore != NULL) ? 1 : 0) + ((dumpnr >= 0) ? 1 : 0) +
375 ((remote != NULL) ? 1 : 0) > 1) {
376 warnx("options -c, -n and -r are mutually exclusive");
377 usage();
378 /* NOTREACHED */
379 }
380
381 if (verbose > 1)
382 warnx("using %s as the crash directory", crashdir);
383
384 if (argc > optind)
385 kernel = strdup(argv[optind++]);
386
387 if (argc > optind && (dumpnr >= 0 || remote != NULL)) {
388 warnx("options -n and -r do not take a core file. Ignored");
389 optind = argc;
390 }
391
392 if (dumpnr >= 0) {
393 snprintf(path, sizeof(path), "%s/vmcore.%d", crashdir, dumpnr);
394 if (stat(path, &st) == -1)
395 err(1, path);
396 if (!S_ISREG(st.st_mode))
397 errx(1, "%s: not a regular file", path);
398 vmcore = strdup(path);
399 } else if (remote != NULL && remote[0] != ':' && remote[0] != '|') {
400 if (stat(remote, &st) != 0) {
401 snprintf(path, sizeof(path), "/dev/%s", remote);
402 if (stat(path, &st) != 0) {
403 err(1, "%s", remote);
404 /* NOTREACHED */
405 }
406 free(remote);
407 remote = strdup(path);
408 }
409 if (!S_ISCHR(st.st_mode) && !S_ISFIFO(st.st_mode)) {
410 errx(1, "%s: not a special file, FIFO or socket",
411 remote);
412 /* NOTREACHED */
413 }
414 } else if (argc > optind) {
415 if (vmcore == NULL)
416 vmcore = strdup(argv[optind++]);
417 if (argc > optind)
418 warnx("multiple core files specified. Ignored");
419 } else if (vmcore == NULL && kernel == NULL) {
420 vmcore = strdup(_PATH_MEM);
421 kernel = strdup(getbootfile());
422 }
423
424 if (verbose) {
425 if (vmcore != NULL)
426 warnx("core file: %s", vmcore);
427 if (remote != NULL)
428 warnx("device file: %s", remote);
429 if (kernel != NULL)
430 warnx("kernel image: %s", kernel);
431 }
432
433 /*
434 * At this point we must either have a core file or have a kernel
435 * with a remote target.
436 */
437 if (remote != NULL && kernel == NULL) {
438 warnx("remote debugging requires a kernel");
439 usage();
440 /* NOTREACHED */
441 }
442 if (vmcore == NULL && remote == NULL) {
443 warnx("need a core file or a device for remote debugging");
444 usage();
445 /* NOTREACHED */
446 }
447
448 /* If we don't have a kernel image yet, try to find one. */
449 if (kernel == NULL) {
450 if (dumpnr >= 0)
451 kernel_from_dumpnr(dumpnr);
452
453 if (kernel == NULL)
454 errx(1, "couldn't find a suitable kernel image");
455 if (verbose)
456 warnx("kernel image: %s", kernel);
457 }
458
459 if (remote == NULL) {
460 kvm = kvm_openfiles(kernel, vmcore, NULL, O_RDONLY, kvm_err);
461 if (kvm == NULL)
462 errx(1, kvm_err);
463 atexit(kgdb_atexit);
464 kgdb_thr_init();
465 }
466
467 /* The libgdb code uses optind too. Reset it... */
468 optind = 0;
469
470 memset (&args, 0, sizeof args);
471 args.argv = argv;
472 args.argc = 1 + quiet;
473 if (quiet)
474 argv[1] = "-q";
475 argv[args.argc] = NULL;
476 args.use_windows = 0;
477 args.interpreter_p = "kgdb";
478
479 init_ui_hook = kgdb_init;
480
67extern void symbol_file_add_main (char *args, int from_tty);
68
69#include "kgdb.h"
70
71kvm_t *kvm;
72static char kvm_err[_POSIX2_LINE_MAX];
73
74static int dumpnr;
75static int verbose;
76
77static char crashdir[PATH_MAX];
78static char *kernel;
79static char *remote;
80static char *vmcore;
81
82static void (*kgdb_new_objfile_chain)(struct objfile * objfile);
83
84static void
85kgdb_atexit(void)
86{
87 if (kvm != NULL)
88 kvm_close(kvm);
89}
90
91static void
92usage(void)
93{
94
95 fprintf(stderr,
96 "usage: %s [-afqv] [-d crashdir] [-c core | -n dumpnr | -r device]\n"
97 "\t[kernel [core]]\n", getprogname());
98 exit(1);
99}
100
101static void
102kernel_from_dumpnr(int nr)
103{
104 char path[PATH_MAX];
105 FILE *info;
106 char *s;
107 struct stat st;
108 int l;
109
110 /*
111 * If there's a kernel image right here in the crash directory, then
112 * use it. The kernel image is either called kernel.<nr> or is in a
113 * subdirectory kernel.<nr> and called kernel. The latter allows us
114 * to collect the modules in the same place.
115 */
116 snprintf(path, sizeof(path), "%s/kernel.%d", crashdir, nr);
117 if (stat(path, &st) == 0) {
118 if (S_ISREG(st.st_mode)) {
119 kernel = strdup(path);
120 return;
121 }
122 if (S_ISDIR(st.st_mode)) {
123 snprintf(path, sizeof(path), "%s/kernel.%d/kernel",
124 crashdir, nr);
125 if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) {
126 kernel = strdup(path);
127 return;
128 }
129 }
130 }
131
132 /*
133 * No kernel image here. Parse the dump header. The kernel object
134 * directory can be found there and we probably have the kernel
135 * image still in it. The object directory may also have a kernel
136 * with debugging info (called kernel.debug). If we have a debug
137 * kernel, use it.
138 */
139 snprintf(path, sizeof(path), "%s/info.%d", crashdir, nr);
140 info = fopen(path, "r");
141 if (info == NULL) {
142 warn(path);
143 return;
144 }
145 while (fgets(path, sizeof(path), info) != NULL) {
146 l = strlen(path);
147 if (l > 0 && path[l - 1] == '\n')
148 path[--l] = '\0';
149 if (strncmp(path, " ", 4) == 0) {
150 s = strchr(path, ':');
151 s = (s == NULL) ? path + 4 : s + 1;
152 l = snprintf(path, sizeof(path), "%s/kernel.debug", s);
153 if (stat(path, &st) == -1 || !S_ISREG(st.st_mode)) {
154 path[l - 6] = '\0';
155 if (stat(path, &st) == -1 ||
156 !S_ISREG(st.st_mode))
157 break;
158 }
159 kernel = strdup(path);
160 break;
161 }
162 }
163 fclose(info);
164}
165
166static void
167kgdb_new_objfile(struct objfile *objfile)
168{
169#if 0
170 printf("XXX: %s(%p)\n", __func__, objfile);
171 if (objfile != NULL) {
172 goto out;
173 }
174
175out:
176#endif
177 if (kgdb_new_objfile_chain != NULL)
178 kgdb_new_objfile_chain(objfile);
179}
180
181static CORE_ADDR
182kgdb_parse(const char *exp)
183{
184 struct cleanup *old_chain;
185 struct expression *expr;
186 struct value *val;
187 char *s;
188 CORE_ADDR n;
189
190 s = strdup(exp);
191 old_chain = make_cleanup(free_current_contents, &expr);
192 expr = parse_expression(s);
193 val = (expr != NULL) ? evaluate_expression(expr) : NULL;
194 n = (val != NULL) ? value_as_address(val) : 0;
195 do_cleanups(old_chain);
196 free(s);
197 return (n);
198}
199
200static void
201kgdb_init_target(void)
202{
203 CORE_ADDR bufp;
204 bfd *kern_bfd;
205 int size, rseq, wseq;
206 int kern_desc;
207 char c;
208
209 kern_desc = open(kernel, O_RDONLY);
210 if (kern_desc == -1)
211 errx(1, "couldn't open a kernel image");
212
213 kern_bfd = bfd_fdopenr(kernel, gnutarget, kern_desc);
214 if (kern_bfd == NULL) {
215 close(kern_desc);
216 errx(1, "\"%s\": can't open to probe ABI: %s.", kernel,
217 bfd_errmsg (bfd_get_error ()));
218 }
219 bfd_set_cacheable(kern_bfd, 1);
220
221 if (!bfd_check_format (kern_bfd, bfd_object)) {
222 bfd_close(kern_bfd);
223 errx(1, "\"%s\": not in executable format: %s", kernel,
224 bfd_errmsg(bfd_get_error()));
225 }
226
227 set_gdbarch_from_file (kern_bfd);
228 bfd_close(kern_bfd);
229
230 symbol_file_add_main (kernel, 0);
231 if (remote)
232 push_remote_target (remote, 0);
233 else
234 kgdb_target();
235
236 /*
237 * Display the unread portion of the message buffer. This gives the
238 * user a some initial data to work from.
239 */
240 bufp = kgdb_parse("msgbufp->msg_ptr");
241 size = (int)kgdb_parse("msgbufp->msg_size");
242 rseq = (int)kgdb_parse("msgbufp->msg_rseq");
243 wseq = (int)kgdb_parse("msgbufp->msg_wseq");
244 if (bufp == 0 || size == 0 || rseq == wseq)
245 return;
246
247 printf("\nUnread portion of the kernel message buffer:\n");
248 while (rseq < wseq) {
249 read_memory(bufp + rseq, &c, 1);
250 putchar(c);
251 rseq++;
252 if (rseq == size)
253 rseq = 0;
254 }
255 if (c != '\n')
256 putchar('\n');
257 putchar('\n');
258}
259
260static void
261kgdb_interp_command_loop(void *data)
262{
263 static int once = 0;
264
265 if (!once) {
266 once = 1;
267 kgdb_init_target();
268 print_stack_frame(get_selected_frame(),
269 frame_relative_level(get_selected_frame()), 1);
270 }
271 command_loop();
272}
273
274static void
275kgdb_init(char *argv0 __unused)
276{
277 static struct interp_procs procs = {
278 NULL,
279 NULL,
280 NULL,
281 NULL,
282 NULL,
283 kgdb_interp_command_loop
284 };
285 struct interp *kgdb;
286 kgdb = interp_new("kgdb", NULL, cli_out_new(gdb_stdout), &procs);
287 interp_add(kgdb);
288
289 set_prompt("(kgdb) ");
290 kgdb_new_objfile_chain = target_new_objfile_hook;
291 target_new_objfile_hook = kgdb_new_objfile;
292}
293
294int
295main(int argc, char *argv[])
296{
297 char path[PATH_MAX];
298 struct stat st;
299 struct captured_main_args args;
300 char *s;
301 int a, ch, quiet;
302
303 dumpnr = -1;
304
305 strlcpy(crashdir, "/var/crash", sizeof(crashdir));
306 s = getenv("KGDB_CRASH_DIR");
307 if (s != NULL)
308 strlcpy(crashdir, s, sizeof(crashdir));
309
310 /* Convert long options into short options. */
311 for (a = 1; a < argc; a++) {
312 s = argv[a];
313 if (s[0] == '-') {
314 s++;
315 /* Long options take either 1 or 2 dashes. */
316 if (s[0] == '-')
317 s++;
318 if (strcmp(s, "quiet") == 0)
319 argv[a] = "-q";
320 else if (strcmp(s, "fullname") == 0)
321 argv[a] = "-f";
322 }
323 }
324
325 quiet = 0;
326
327 while ((ch = getopt(argc, argv, "ac:d:fn:qr:v")) != -1) {
328 switch (ch) {
329 case 'a':
330 annotation_level++;
331 break;
332 case 'c': /* use given core file. */
333 if (vmcore != NULL) {
334 warnx("option %c: can only be specified once",
335 optopt);
336 usage();
337 /* NOTREACHED */
338 }
339 vmcore = strdup(optarg);
340 break;
341 case 'd': /* lookup dumps in given directory. */
342 strlcpy(crashdir, optarg, sizeof(crashdir));
343 break;
344 case 'f':
345 annotation_level = 1;
346 break;
347 case 'n': /* use dump with given number. */
348 dumpnr = strtol(optarg, &s, 0);
349 if (dumpnr < 0 || *s != '\0') {
350 warnx("option %c: invalid kernel dump number",
351 optopt);
352 usage();
353 /* NOTREACHED */
354 }
355 break;
356 case 'q':
357 quiet = 1;
358 break;
359 case 'r': /* use given device for remote session. */
360 if (remote != NULL) {
361 warnx("option %c: can only be specified once",
362 optopt);
363 usage();
364 /* NOTREACHED */
365 }
366 remote = strdup(optarg);
367 break;
368 case 'v': /* increase verbosity. */
369 verbose++;
370 break;
371 case '?':
372 default:
373 usage();
374 }
375 }
376
377 if (((vmcore != NULL) ? 1 : 0) + ((dumpnr >= 0) ? 1 : 0) +
378 ((remote != NULL) ? 1 : 0) > 1) {
379 warnx("options -c, -n and -r are mutually exclusive");
380 usage();
381 /* NOTREACHED */
382 }
383
384 if (verbose > 1)
385 warnx("using %s as the crash directory", crashdir);
386
387 if (argc > optind)
388 kernel = strdup(argv[optind++]);
389
390 if (argc > optind && (dumpnr >= 0 || remote != NULL)) {
391 warnx("options -n and -r do not take a core file. Ignored");
392 optind = argc;
393 }
394
395 if (dumpnr >= 0) {
396 snprintf(path, sizeof(path), "%s/vmcore.%d", crashdir, dumpnr);
397 if (stat(path, &st) == -1)
398 err(1, path);
399 if (!S_ISREG(st.st_mode))
400 errx(1, "%s: not a regular file", path);
401 vmcore = strdup(path);
402 } else if (remote != NULL && remote[0] != ':' && remote[0] != '|') {
403 if (stat(remote, &st) != 0) {
404 snprintf(path, sizeof(path), "/dev/%s", remote);
405 if (stat(path, &st) != 0) {
406 err(1, "%s", remote);
407 /* NOTREACHED */
408 }
409 free(remote);
410 remote = strdup(path);
411 }
412 if (!S_ISCHR(st.st_mode) && !S_ISFIFO(st.st_mode)) {
413 errx(1, "%s: not a special file, FIFO or socket",
414 remote);
415 /* NOTREACHED */
416 }
417 } else if (argc > optind) {
418 if (vmcore == NULL)
419 vmcore = strdup(argv[optind++]);
420 if (argc > optind)
421 warnx("multiple core files specified. Ignored");
422 } else if (vmcore == NULL && kernel == NULL) {
423 vmcore = strdup(_PATH_MEM);
424 kernel = strdup(getbootfile());
425 }
426
427 if (verbose) {
428 if (vmcore != NULL)
429 warnx("core file: %s", vmcore);
430 if (remote != NULL)
431 warnx("device file: %s", remote);
432 if (kernel != NULL)
433 warnx("kernel image: %s", kernel);
434 }
435
436 /*
437 * At this point we must either have a core file or have a kernel
438 * with a remote target.
439 */
440 if (remote != NULL && kernel == NULL) {
441 warnx("remote debugging requires a kernel");
442 usage();
443 /* NOTREACHED */
444 }
445 if (vmcore == NULL && remote == NULL) {
446 warnx("need a core file or a device for remote debugging");
447 usage();
448 /* NOTREACHED */
449 }
450
451 /* If we don't have a kernel image yet, try to find one. */
452 if (kernel == NULL) {
453 if (dumpnr >= 0)
454 kernel_from_dumpnr(dumpnr);
455
456 if (kernel == NULL)
457 errx(1, "couldn't find a suitable kernel image");
458 if (verbose)
459 warnx("kernel image: %s", kernel);
460 }
461
462 if (remote == NULL) {
463 kvm = kvm_openfiles(kernel, vmcore, NULL, O_RDONLY, kvm_err);
464 if (kvm == NULL)
465 errx(1, kvm_err);
466 atexit(kgdb_atexit);
467 kgdb_thr_init();
468 }
469
470 /* The libgdb code uses optind too. Reset it... */
471 optind = 0;
472
473 memset (&args, 0, sizeof args);
474 args.argv = argv;
475 args.argc = 1 + quiet;
476 if (quiet)
477 argv[1] = "-q";
478 argv[args.argc] = NULL;
479 args.use_windows = 0;
480 args.interpreter_p = "kgdb";
481
482 init_ui_hook = kgdb_init;
483
484 kgdb_sniffer_kluge = kgdb_trgt_trapframe_sniffer;
485
481 return (gdb_main(&args));
482}
486 return (gdb_main(&args));
487}