main.c revision 175416
1184610Salfred/*
2184610Salfred * Copyright (c) 2004 Marcel Moolenaar
3184610Salfred * All rights reserved.
4184610Salfred *
5184610Salfred * Redistribution and use in source and binary forms, with or without
6184610Salfred * modification, are permitted provided that the following conditions
7184610Salfred * are met:
8184610Salfred *
9184610Salfred * 1. Redistributions of source code must retain the above copyright
10184610Salfred *    notice, this list of conditions and the following disclaimer.
11184610Salfred * 2. Redistributions in binary form must reproduce the above copyright
12184610Salfred *    notice, this list of conditions and the following disclaimer in the
13184610Salfred *    documentation and/or other materials provided with the distribution.
14184610Salfred *
15184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16184610Salfred * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17184610Salfred * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18184610Salfred * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19184610Salfred * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20184610Salfred * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21184610Salfred * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22184610Salfred * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23184610Salfred * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24184610Salfred * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25184610Salfred */
26184610Salfred
27184610Salfred#include <sys/cdefs.h>
28184610Salfred__FBSDID("$FreeBSD: head/gnu/usr.bin/gdb/kgdb/main.c 175416 2008-01-17 21:43:12Z jhb $");
29184610Salfred
30184610Salfred#include <sys/param.h>
31184610Salfred#include <sys/stat.h>
32184610Salfred#include <sys/types.h>
33184610Salfred#include <sys/ioctl.h>
34184610Salfred#include <sys/resource.h>
35184610Salfred#include <sys/select.h>
36184610Salfred#include <sys/time.h>
37184610Salfred#include <sys/wait.h>
38184610Salfred#include <errno.h>
39184610Salfred#include <err.h>
40184610Salfred#include <fcntl.h>
41184610Salfred#include <inttypes.h>
42184610Salfred#include <kvm.h>
43184610Salfred#include <limits.h>
44184610Salfred#include <paths.h>
45184610Salfred#include <stdio.h>
46184610Salfred#include <stdlib.h>
47184610Salfred#include <string.h>
48184610Salfred#include <unistd.h>
49184610Salfred
50184610Salfred/* libgdb stuff. */
51184610Salfred#include <defs.h>
52184610Salfred#include <frame.h>
53184610Salfred#include <frame-unwind.h>
54184610Salfred#include <inferior.h>
55184610Salfred#include <interps.h>
56184610Salfred#include <cli-out.h>
57184610Salfred#include <main.h>
58184610Salfred#include <target.h>
59184610Salfred#include <top.h>
60184610Salfred#include <bfd.h>
61184610Salfred#include <gdbcore.h>
62184610Salfred
63184610Salfredextern void (*init_ui_hook)(char *);
64184610Salfred
65184610Salfredextern frame_unwind_sniffer_ftype *kgdb_sniffer_kluge;
66184610Salfred
67184610Salfredextern void symbol_file_add_main (char *args, int from_tty);
68184610Salfred
69184610Salfred#include "kgdb.h"
70184610Salfred
71184610Salfredkvm_t *kvm;
72184610Salfredstatic char kvm_err[_POSIX2_LINE_MAX];
73184610Salfred
74184610Salfredstatic int dumpnr;
75184610Salfredstatic int verbose;
76184610Salfred
77184610Salfredstatic char crashdir[PATH_MAX];
78184610Salfredchar *kernel;
79184610Salfredstatic char *remote;
80184610Salfredstatic char *vmcore;
81188622Sthompsa
82188622Sthompsastatic void (*kgdb_new_objfile_chain)(struct objfile * objfile);
83184610Salfred
84184610Salfredstatic void
85184610Salfredkgdb_atexit(void)
86184610Salfred{
87184610Salfred	if (kvm != NULL)
88184610Salfred		kvm_close(kvm);
89184610Salfred}
90184610Salfred
91184610Salfredstatic void
92184610Salfredusage(void)
93184610Salfred{
94184610Salfred
95184610Salfred	fprintf(stderr,
96184610Salfred	    "usage: %s [-afqv] [-d crashdir] [-c core | -n dumpnr | -r device]\n"
97184610Salfred	    "\t[kernel [core]]\n", getprogname());
98184610Salfred	exit(1);
99184610Salfred}
100184610Salfred
101184610Salfredstatic void
102184610Salfredkernel_from_dumpnr(int nr)
103184610Salfred{
104188622Sthompsa	char path[PATH_MAX];
105184610Salfred	FILE *info;
106184610Salfred	char *s;
107184610Salfred	struct stat st;
108184610Salfred	int l;
109184610Salfred
110184610Salfred	/*
111184610Salfred	 * If there's a kernel image right here in the crash directory, then
112184610Salfred	 * use it.  The kernel image is either called kernel.<nr> or is in a
113184610Salfred	 * subdirectory kernel.<nr> and called kernel.  The latter allows us
114188622Sthompsa	 * to collect the modules in the same place.
115184610Salfred	 */
116184610Salfred	snprintf(path, sizeof(path), "%s/kernel.%d", crashdir, nr);
117184610Salfred	if (stat(path, &st) == 0) {
118184610Salfred		if (S_ISREG(st.st_mode)) {
119184610Salfred			kernel = strdup(path);
120184610Salfred			return;
121184610Salfred		}
122184610Salfred		if (S_ISDIR(st.st_mode)) {
123184610Salfred			snprintf(path, sizeof(path), "%s/kernel.%d/kernel",
124184610Salfred			    crashdir, nr);
125184610Salfred			if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) {
126184610Salfred				kernel = strdup(path);
127188622Sthompsa				return;
128184610Salfred			}
129184610Salfred		}
130184610Salfred	}
131184610Salfred
132184610Salfred	/*
133184610Salfred	 * No kernel image here.  Parse the dump header.  The kernel object
134184610Salfred	 * directory can be found there and we probably have the kernel
135184610Salfred	 * image still in it.  The object directory may also have a kernel
136184610Salfred	 * with debugging info (called kernel.debug).  If we have a debug
137184610Salfred	 * kernel, use it.
138184610Salfred	 */
139184610Salfred	snprintf(path, sizeof(path), "%s/info.%d", crashdir, nr);
140184610Salfred	info = fopen(path, "r");
141184610Salfred	if (info == NULL) {
142184610Salfred		warn(path);
143184610Salfred		return;
144184610Salfred	}
145184610Salfred	while (fgets(path, sizeof(path), info) != NULL) {
146184610Salfred		l = strlen(path);
147184610Salfred		if (l > 0 && path[l - 1] == '\n')
148184610Salfred			path[--l] = '\0';
149184610Salfred		if (strncmp(path, "    ", 4) == 0) {
150184610Salfred			s = strchr(path, ':');
151184610Salfred			s = (s == NULL) ? path + 4 : s + 1;
152184610Salfred			l = snprintf(path, sizeof(path), "%s/kernel.debug", s);
153184610Salfred			if (stat(path, &st) == -1 || !S_ISREG(st.st_mode)) {
154184610Salfred				path[l - 6] = '\0';
155184610Salfred				if (stat(path, &st) == -1 ||
156184610Salfred				    !S_ISREG(st.st_mode))
157184610Salfred					break;
158184610Salfred			}
159184610Salfred			kernel = strdup(path);
160184610Salfred			break;
161184610Salfred		}
162184610Salfred	}
163184610Salfred	fclose(info);
164184610Salfred}
165184610Salfred
166184610Salfredstatic void
167184610Salfredkgdb_new_objfile(struct objfile *objfile)
168184610Salfred{
169184610Salfred#if 0
170184610Salfred	printf("XXX: %s(%p)\n", __func__, objfile);
171184610Salfred	if (objfile != NULL) {
172184610Salfred		goto out;
173188622Sthompsa	}
174184610Salfred
175184610Salfredout:
176184610Salfred#endif
177184610Salfred	if (kgdb_new_objfile_chain != NULL)
178184610Salfred		kgdb_new_objfile_chain(objfile);
179184610Salfred}
180184610Salfred
181184610SalfredCORE_ADDR
182184610Salfredkgdb_parse(const char *exp)
183184610Salfred{
184184610Salfred	struct cleanup *old_chain;
185184610Salfred	struct expression *expr;
186184610Salfred	struct value *val;
187184610Salfred	char *s;
188184610Salfred	CORE_ADDR n;
189184610Salfred
190184610Salfred	s = strdup(exp);
191184610Salfred	old_chain = make_cleanup(free_current_contents, &expr);
192184610Salfred	expr = parse_expression(s);
193184610Salfred	val = (expr != NULL) ? evaluate_expression(expr) : NULL;
194184610Salfred	n = (val != NULL) ? value_as_address(val) : 0;
195184610Salfred	do_cleanups(old_chain);
196184610Salfred	free(s);
197184610Salfred	return (n);
198184610Salfred}
199184610Salfred
200184610Salfred#define	MSGBUF_SEQ_TO_POS(size, seq)	((seq) % (size))
201184610Salfred
202184610Salfredstatic void
203184610Salfredkgdb_init_target(void)
204184610Salfred{
205184610Salfred	CORE_ADDR bufp;
206184610Salfred	bfd *kern_bfd;
207184610Salfred	int size, rseq, wseq;
208184610Salfred	int kern_desc;
209184610Salfred	char c;
210184610Salfred
211184610Salfred	kern_desc = open(kernel, O_RDONLY);
212184610Salfred	if (kern_desc == -1)
213184610Salfred		errx(1, "couldn't open a kernel image");
214184610Salfred
215184610Salfred	kern_bfd = bfd_fdopenr(kernel, gnutarget, kern_desc);
216184610Salfred	if (kern_bfd == NULL) {
217184610Salfred		close(kern_desc);
218184610Salfred		errx(1, "\"%s\": can't open to probe ABI: %s.", kernel,
219184610Salfred			bfd_errmsg (bfd_get_error ()));
220184610Salfred	}
221184610Salfred	bfd_set_cacheable(kern_bfd, 1);
222184610Salfred
223184610Salfred	if (!bfd_check_format (kern_bfd, bfd_object)) {
224184610Salfred		bfd_close(kern_bfd);
225184610Salfred		errx(1, "\"%s\": not in executable format: %s", kernel,
226184610Salfred			bfd_errmsg(bfd_get_error()));
227184610Salfred        }
228184610Salfred
229184610Salfred	set_gdbarch_from_file (kern_bfd);
230184610Salfred	bfd_close(kern_bfd);
231184610Salfred
232184610Salfred	symbol_file_add_main (kernel, 0);
233184610Salfred	if (remote)
234184610Salfred		push_remote_target (remote, 0);
235184610Salfred	else
236184610Salfred		kgdb_target();
237184610Salfred
238184610Salfred	/*
239184610Salfred	 * Display the unread portion of the message buffer. This gives the
240184610Salfred	 * user a some initial data to work from.
241184610Salfred	 */
242184610Salfred	bufp = kgdb_parse("msgbufp->msg_ptr");
243184610Salfred	size = (int)kgdb_parse("msgbufp->msg_size");
244184610Salfred	rseq = (int)kgdb_parse("msgbufp->msg_rseq");
245184610Salfred	wseq = (int)kgdb_parse("msgbufp->msg_wseq");
246184610Salfred	rseq = MSGBUF_SEQ_TO_POS(size, rseq);
247184610Salfred	wseq = MSGBUF_SEQ_TO_POS(size, wseq);
248184610Salfred	if (bufp == 0 || size == 0 || rseq == wseq)
249184610Salfred		return;
250184610Salfred
251184610Salfred	printf("\nUnread portion of the kernel message buffer:\n");
252184610Salfred	while (rseq < wseq) {
253184610Salfred		read_memory(bufp + rseq, &c, 1);
254184610Salfred		putchar(c);
255184610Salfred		rseq++;
256184610Salfred		if (rseq == size)
257184610Salfred			rseq = 0;
258184610Salfred	}
259184610Salfred	if (c != '\n')
260184610Salfred		putchar('\n');
261184610Salfred	putchar('\n');
262184610Salfred}
263184610Salfred
264184610Salfredstatic void
265184610Salfredkgdb_interp_command_loop(void *data)
266184610Salfred{
267184610Salfred	static int once = 0;
268184610Salfred
269184610Salfred	if (!once) {
270184610Salfred		once = 1;
271184610Salfred		kgdb_init_target();
272184610Salfred		print_stack_frame(get_selected_frame(),
273184610Salfred		    frame_relative_level(get_selected_frame()), 1);
274184610Salfred	}
275184610Salfred	command_loop();
276184610Salfred}
277184610Salfred
278188622Sthompsastatic void
279184610Salfredkgdb_init(char *argv0 __unused)
280184610Salfred{
281184610Salfred	static struct interp_procs procs = {
282184610Salfred		NULL,
283184610Salfred		NULL,
284184610Salfred		NULL,
285184610Salfred		NULL,
286184610Salfred		NULL,
287184610Salfred		kgdb_interp_command_loop
288184610Salfred	};
289184610Salfred	struct interp *kgdb;
290184610Salfred	kgdb = interp_new("kgdb", NULL, cli_out_new(gdb_stdout), &procs);
291184610Salfred	interp_add(kgdb);
292184610Salfred
293184610Salfred	set_prompt("(kgdb) ");
294184610Salfred	kgdb_new_objfile_chain = target_new_objfile_hook;
295184610Salfred	target_new_objfile_hook = kgdb_new_objfile;
296184610Salfred}
297188622Sthompsa
298184610Salfredint
299184610Salfredmain(int argc, char *argv[])
300184610Salfred{
301184610Salfred	char path[PATH_MAX];
302184610Salfred	struct stat st;
303184610Salfred	struct captured_main_args args;
304184610Salfred	char *s;
305184610Salfred	int a, ch, quiet, writecore;
306184610Salfred
307184610Salfred	dumpnr = -1;
308184610Salfred
309184610Salfred	strlcpy(crashdir, "/var/crash", sizeof(crashdir));
310184610Salfred	s = getenv("KGDB_CRASH_DIR");
311184610Salfred	if (s != NULL)
312184610Salfred		strlcpy(crashdir, s, sizeof(crashdir));
313184610Salfred
314184610Salfred	/* Convert long options into short options. */
315184610Salfred	for (a = 1; a < argc; a++) {
316184610Salfred		s = argv[a];
317184610Salfred		if (s[0] == '-') {
318184610Salfred			s++;
319184610Salfred			/* Long options take either 1 or 2 dashes. */
320184610Salfred			if (s[0] == '-')
321184610Salfred				s++;
322184610Salfred			if (strcmp(s, "quiet") == 0)
323184610Salfred				argv[a] = "-q";
324184610Salfred			else if (strcmp(s, "fullname") == 0)
325184610Salfred				argv[a] = "-f";
326184610Salfred		}
327184610Salfred	}
328184610Salfred
329184610Salfred	quiet = 0;
330184610Salfred	writecore = 0;
331184610Salfred
332184610Salfred	while ((ch = getopt(argc, argv, "ac:d:fn:qr:vw")) != -1) {
333184610Salfred		switch (ch) {
334184610Salfred		case 'a':
335184610Salfred			annotation_level++;
336184610Salfred			break;
337184610Salfred		case 'c':	/* use given core file. */
338184610Salfred			if (vmcore != NULL) {
339184610Salfred				warnx("option %c: can only be specified once",
340184610Salfred				    optopt);
341184610Salfred				usage();
342184610Salfred				/* NOTREACHED */
343184610Salfred			}
344184610Salfred			vmcore = strdup(optarg);
345184610Salfred			break;
346184610Salfred		case 'd':	/* lookup dumps in given directory. */
347184610Salfred			strlcpy(crashdir, optarg, sizeof(crashdir));
348184610Salfred			break;
349184610Salfred		case 'f':
350184610Salfred			annotation_level = 1;
351184610Salfred			break;
352184610Salfred		case 'n':	/* use dump with given number. */
353184610Salfred			dumpnr = strtol(optarg, &s, 0);
354184610Salfred			if (dumpnr < 0 || *s != '\0') {
355184610Salfred				warnx("option %c: invalid kernel dump number",
356184610Salfred				    optopt);
357184610Salfred				usage();
358184610Salfred				/* NOTREACHED */
359184610Salfred			}
360184610Salfred			break;
361184610Salfred		case 'q':
362184610Salfred			quiet = 1;
363184610Salfred			break;
364184610Salfred		case 'r':	/* use given device for remote session. */
365184610Salfred			if (remote != NULL) {
366184610Salfred				warnx("option %c: can only be specified once",
367184610Salfred				    optopt);
368184610Salfred				usage();
369184610Salfred				/* NOTREACHED */
370184610Salfred			}
371184610Salfred			remote = strdup(optarg);
372184610Salfred			break;
373184610Salfred		case 'v':	/* increase verbosity. */
374184610Salfred			verbose++;
375184610Salfred			break;
376184610Salfred		case 'w':	/* core file is writeable. */
377184610Salfred			writecore = 1;
378184610Salfred			break;
379184610Salfred		case '?':
380184610Salfred		default:
381184610Salfred			usage();
382184610Salfred		}
383184610Salfred	}
384184610Salfred
385184610Salfred	if (((vmcore != NULL) ? 1 : 0) + ((dumpnr >= 0) ? 1 : 0) +
386184610Salfred	    ((remote != NULL) ? 1 : 0) > 1) {
387184610Salfred		warnx("options -c, -n and -r are mutually exclusive");
388184610Salfred		usage();
389184610Salfred		/* NOTREACHED */
390184610Salfred	}
391184610Salfred
392184610Salfred	if (verbose > 1)
393184610Salfred		warnx("using %s as the crash directory", crashdir);
394184610Salfred
395184610Salfred	if (argc > optind)
396184610Salfred		kernel = strdup(argv[optind++]);
397184610Salfred
398184610Salfred	if (argc > optind && (dumpnr >= 0 || remote != NULL)) {
399184610Salfred		warnx("options -n and -r do not take a core file. Ignored");
400184610Salfred		optind = argc;
401184610Salfred	}
402184610Salfred
403184610Salfred	if (dumpnr >= 0) {
404184610Salfred		snprintf(path, sizeof(path), "%s/vmcore.%d", crashdir, dumpnr);
405184610Salfred		if (stat(path, &st) == -1)
406184610Salfred			err(1, path);
407184610Salfred		if (!S_ISREG(st.st_mode))
408184610Salfred			errx(1, "%s: not a regular file", path);
409184610Salfred		vmcore = strdup(path);
410184610Salfred	} else if (remote != NULL && remote[0] != ':' && remote[0] != '|') {
411184610Salfred		if (stat(remote, &st) != 0) {
412184610Salfred			snprintf(path, sizeof(path), "/dev/%s", remote);
413184610Salfred			if (stat(path, &st) != 0) {
414184610Salfred				err(1, "%s", remote);
415184610Salfred				/* NOTREACHED */
416184610Salfred			}
417184610Salfred			free(remote);
418184610Salfred			remote = strdup(path);
419184610Salfred		}
420184610Salfred		if (!S_ISCHR(st.st_mode) && !S_ISFIFO(st.st_mode)) {
421184610Salfred			errx(1, "%s: not a special file, FIFO or socket",
422184610Salfred			    remote);
423184610Salfred			/* NOTREACHED */
424184610Salfred		}
425188622Sthompsa	} else if (argc > optind) {
426184610Salfred		if (vmcore == NULL)
427184610Salfred			vmcore = strdup(argv[optind++]);
428184610Salfred		if (argc > optind)
429184610Salfred			warnx("multiple core files specified. Ignored");
430184610Salfred	} else if (vmcore == NULL && kernel == NULL) {
431184610Salfred		vmcore = strdup(_PATH_MEM);
432184610Salfred		kernel = strdup(getbootfile());
433184610Salfred	}
434184610Salfred
435184610Salfred	if (verbose) {
436184610Salfred		if (vmcore != NULL)
437184610Salfred			warnx("core file: %s", vmcore);
438184610Salfred		if (remote != NULL)
439184610Salfred			warnx("device file: %s", remote);
440184610Salfred		if (kernel != NULL)
441184610Salfred			warnx("kernel image: %s", kernel);
442184610Salfred	}
443184610Salfred
444184610Salfred	/*
445184610Salfred	 * At this point we must either have a core file or have a kernel
446184610Salfred	 * with a remote target.
447184610Salfred	 */
448184610Salfred	if (remote != NULL && kernel == NULL) {
449184610Salfred		warnx("remote debugging requires a kernel");
450184610Salfred		usage();
451184610Salfred		/* NOTREACHED */
452184610Salfred	}
453184610Salfred	if (vmcore == NULL && remote == NULL) {
454184610Salfred		warnx("need a core file or a device for remote debugging");
455184610Salfred		usage();
456184610Salfred		/* NOTREACHED */
457188622Sthompsa	}
458184610Salfred
459184610Salfred	/* If we don't have a kernel image yet, try to find one. */
460184610Salfred	if (kernel == NULL) {
461184610Salfred		if (dumpnr >= 0)
462184610Salfred			kernel_from_dumpnr(dumpnr);
463184610Salfred
464184610Salfred		if (kernel == NULL)
465184610Salfred			errx(1, "couldn't find a suitable kernel image");
466184610Salfred		if (verbose)
467184610Salfred			warnx("kernel image: %s", kernel);
468184610Salfred	}
469184610Salfred
470184610Salfred	if (remote == NULL) {
471184610Salfred		kvm = kvm_openfiles(kernel, vmcore, NULL,
472184610Salfred		    writecore ? O_RDWR : O_RDONLY, kvm_err);
473184610Salfred		if (kvm == NULL)
474184610Salfred			errx(1, kvm_err);
475184610Salfred		atexit(kgdb_atexit);
476184610Salfred		kgdb_thr_init();
477184610Salfred	}
478184610Salfred
479184610Salfred	/* The libgdb code uses optind too. Reset it... */
480184610Salfred	optind = 0;
481184610Salfred
482184610Salfred	memset (&args, 0, sizeof args);
483184610Salfred	args.argv = argv;
484184610Salfred	args.argc = 1 + quiet;
485188622Sthompsa	if (quiet)
486184610Salfred		argv[1] = "-q";
487184610Salfred	argv[args.argc] = NULL;
488184610Salfred	args.use_windows = 0;
489184610Salfred	args.interpreter_p = "kgdb";
490184610Salfred
491187184Sthompsa	init_ui_hook = kgdb_init;
492187184Sthompsa
493184610Salfred	kgdb_sniffer_kluge = kgdb_trgt_trapframe_sniffer;
494184610Salfred
495184610Salfred	return (gdb_main(&args));
496184610Salfred}
497184610Salfred