Deleted Added
sdiff udiff text old ( 148801 ) new ( 149954 )
full compact
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 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>
53#include <frame-unwind.h>
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
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
486 return (gdb_main(&args));
487}