main.c revision 245705
11590Srgrimes/*
21590Srgrimes * Copyright (c) 2004 Marcel Moolenaar
31590Srgrimes * All rights reserved.
41590Srgrimes *
51590Srgrimes * Redistribution and use in source and binary forms, with or without
61590Srgrimes * modification, are permitted provided that the following conditions
71590Srgrimes * are met:
81590Srgrimes *
91590Srgrimes * 1. Redistributions of source code must retain the above copyright
101590Srgrimes *    notice, this list of conditions and the following disclaimer.
111590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
121590Srgrimes *    notice, this list of conditions and the following disclaimer in the
131590Srgrimes *    documentation and/or other materials provided with the distribution.
141590Srgrimes *
151590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
161590Srgrimes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
171590Srgrimes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
181590Srgrimes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
191590Srgrimes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
201590Srgrimes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
211590Srgrimes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
221590Srgrimes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
231590Srgrimes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
241590Srgrimes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
251590Srgrimes */
261590Srgrimes
271590Srgrimes#include <sys/cdefs.h>
281590Srgrimes__FBSDID("$FreeBSD: head/gnu/usr.bin/gdb/kgdb/main.c 245705 2013-01-21 01:46:36Z adrian $");
291590Srgrimes
301590Srgrimes#include <sys/param.h>
311590Srgrimes#include <sys/stat.h>
321590Srgrimes#include <sys/types.h>
331590Srgrimes#include <sys/ioctl.h>
341590Srgrimes#include <sys/resource.h>
351590Srgrimes#include <sys/select.h>
36116390Scharnier#include <sys/time.h>
371590Srgrimes#include <sys/wait.h>
381590Srgrimes#include <errno.h>
39116390Scharnier#include <err.h>
4027419Scharnier#include <inttypes.h>
41116390Scharnier#include <kvm.h>
4299112Sobrien#include <limits.h>
4399112Sobrien#include <paths.h>
441590Srgrimes#include <stdio.h>
4527419Scharnier#include <stdlib.h>
4627419Scharnier#include <string.h>
471590Srgrimes#include <unistd.h>
481590Srgrimes
491590Srgrimes/* libgdb stuff. */
501590Srgrimes#include <defs.h>
5185632Sschweikh#include <frame.h>
521590Srgrimes#include <frame-unwind.h>
531590Srgrimes#include <inferior.h>
5485632Sschweikh#include <interps.h>
5585632Sschweikh#include <cli-out.h>
561590Srgrimes#include <main.h>
5785632Sschweikh#include <objfiles.h>
5885632Sschweikh#include <target.h>
591590Srgrimes#include <top.h>
601590Srgrimes#include <ui-file.h>
611590Srgrimes#include <bfd.h>
621590Srgrimes#include <gdbcore.h>
631590Srgrimes#include <wrapper.h>
6498771Sjmallett
6585632Sschweikhextern frame_unwind_sniffer_ftype *kgdb_sniffer_kluge;
6685632Sschweikh
671590Srgrimes#include "kgdb.h"
681590Srgrimes
691590Srgrimesstatic int dumpnr;
701590Srgrimesstatic int quiet;
711590Srgrimesstatic int verbose;
721590Srgrimes
731590Srgrimesstatic char crashdir[PATH_MAX];
741590Srgrimesstatic char *kernel;
751590Srgrimesstatic char *remote;
761590Srgrimesstatic char *vmcore;
771590Srgrimesstatic struct ui_file *parse_gdberr;
781590Srgrimes
791590Srgrimesstatic void (*kgdb_new_objfile_chain)(struct objfile * objfile);
801590Srgrimes
811590Srgrimesstatic void
821590Srgrimesusage(void)
831590Srgrimes{
841590Srgrimes
851590Srgrimes	fprintf(stderr,
861590Srgrimes	    "usage: %s [-afqvw] [-d crashdir] [-c core | -n dumpnr | -r device]\n"
871590Srgrimes	    "\t[kernel [core]]\n", getprogname());
881590Srgrimes	exit(1);
891590Srgrimes}
9048566Sbillf
911590Srgrimesstatic void
921590Srgrimeskernel_from_dumpnr(int nr)
931590Srgrimes{
941590Srgrimes	char path[PATH_MAX];
951590Srgrimes	FILE *info;
961590Srgrimes	char *s;
971590Srgrimes	struct stat st;
981590Srgrimes	int l;
9948566Sbillf
1001590Srgrimes	/*
1011590Srgrimes	 * If there's a kernel image right here in the crash directory, then
1021590Srgrimes	 * use it.  The kernel image is either called kernel.<nr> or is in a
1031590Srgrimes	 * subdirectory kernel.<nr> and called kernel.  The latter allows us
1041590Srgrimes	 * to collect the modules in the same place.
1051590Srgrimes	 */
1061590Srgrimes	snprintf(path, sizeof(path), "%s/kernel.%d", crashdir, nr);
1071590Srgrimes	if (stat(path, &st) == 0) {
1081590Srgrimes		if (S_ISREG(st.st_mode)) {
1091590Srgrimes			kernel = strdup(path);
1101590Srgrimes			return;
1111590Srgrimes		}
1121590Srgrimes		if (S_ISDIR(st.st_mode)) {
1131590Srgrimes			snprintf(path, sizeof(path), "%s/kernel.%d/kernel",
1141590Srgrimes			    crashdir, nr);
1151590Srgrimes			if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) {
1161590Srgrimes				kernel = strdup(path);
1171590Srgrimes				return;
1181590Srgrimes			}
1191590Srgrimes		}
1201590Srgrimes	}
1211590Srgrimes
12298771Sjmallett	/*
1231590Srgrimes	 * No kernel image here.  Parse the dump header.  The kernel object
1241590Srgrimes	 * directory can be found there and we probably have the kernel
1251590Srgrimes	 * image still in it.  The object directory may also have a kernel
1261590Srgrimes	 * with debugging info (called kernel.debug).  If we have a debug
1271590Srgrimes	 * kernel, use it.
1281590Srgrimes	 */
1291590Srgrimes	snprintf(path, sizeof(path), "%s/info.%d", crashdir, nr);
13093440Sdwmalone	info = fopen(path, "r");
1311590Srgrimes	if (info == NULL) {
13293440Sdwmalone		warn("%s", path);
1331590Srgrimes		return;
1341590Srgrimes	}
1351590Srgrimes	while (fgets(path, sizeof(path), info) != NULL) {
1361590Srgrimes		l = strlen(path);
1371590Srgrimes		if (l > 0 && path[l - 1] == '\n')
1381590Srgrimes			path[--l] = '\0';
1391590Srgrimes		if (strncmp(path, "    ", 4) == 0) {
1401590Srgrimes			s = strchr(path, ':');
14198771Sjmallett			s = (s == NULL) ? path + 4 : s + 1;
1421590Srgrimes			l = snprintf(path, sizeof(path), "%s/kernel.debug", s);
1431590Srgrimes			if (stat(path, &st) == -1 || !S_ISREG(st.st_mode)) {
1441590Srgrimes				path[l - 6] = '\0';
1451590Srgrimes				if (stat(path, &st) == -1 ||
1461590Srgrimes				    !S_ISREG(st.st_mode))
1471590Srgrimes					break;
1481590Srgrimes			}
14998771Sjmallett			kernel = strdup(path);
1501590Srgrimes			break;
1511590Srgrimes		}
1521590Srgrimes	}
1531590Srgrimes	fclose(info);
1541590Srgrimes}
1551590Srgrimes
1561590Srgrimesstatic void
1571590Srgrimeskgdb_new_objfile(struct objfile *objfile)
1581590Srgrimes{
1591590Srgrimes	static int once = 1;
1601590Srgrimes
1611590Srgrimes	kld_new_objfile(objfile);
1621590Srgrimes	kgdb_trgt_new_objfile(objfile);
16385632Sschweikh
1641590Srgrimes	if (kgdb_new_objfile_chain != NULL)
1651590Srgrimes		kgdb_new_objfile_chain(objfile);
16698771Sjmallett
1671590Srgrimes	if (once && objfile != NULL && objfile == symfile_objfile) {
1681590Srgrimes		/*
1691590Srgrimes		 * The initial kernel has just been loaded.  Start the
1701590Srgrimes		 * remote target if we have one.
1711590Srgrimes		 */
1721590Srgrimes		once = 0;
1731590Srgrimes		if (remote != NULL)
1741590Srgrimes			push_remote_target (remote, 0);
1751590Srgrimes	}
1761590Srgrimes}
1771590Srgrimes
1781590Srgrimes/*
1791590Srgrimes * Parse an expression and return its value.  If 'quiet' is true, then
1801590Srgrimes * any error messages from the parser are masked.
1811590Srgrimes */
1821590SrgrimesCORE_ADDR
1831590Srgrimeskgdb_parse_1(const char *exp, int quiet)
1841590Srgrimes{
1851590Srgrimes	struct ui_file *old_stderr;
1861590Srgrimes	struct cleanup *old_chain;
1871590Srgrimes	struct expression *expr;
1881590Srgrimes	struct value *val;
1891590Srgrimes	char *s;
1901590Srgrimes	CORE_ADDR n;
1911590Srgrimes
19298771Sjmallett	old_stderr = gdb_stderr;
1931590Srgrimes	if (quiet)
1941590Srgrimes		gdb_stderr = parse_gdberr;
1951590Srgrimes	n = 0;
1961590Srgrimes	s = xstrdup(exp);
1971590Srgrimes	old_chain = make_cleanup(xfree, s);
1981590Srgrimes	if (gdb_parse_exp_1(&s, NULL, 0, &expr) && *s == '\0') {
1991590Srgrimes		make_cleanup(free_current_contents, &expr);
2001590Srgrimes		if (gdb_evaluate_expression(expr, &val))
2011590Srgrimes		    n = value_as_address(val);
2021590Srgrimes	}
2031590Srgrimes	do_cleanups(old_chain);
2041590Srgrimes	gdb_stderr = old_stderr;
2051590Srgrimes	return (n);
2061590Srgrimes}
2071590Srgrimes
2081590Srgrimes#define	MSGBUF_SEQ_TO_POS(size, seq)	((seq) % (size))
2091590Srgrimes
2101590Srgrimesvoid
2111590Srgrimeskgdb_dmesg(void)
2121590Srgrimes{
2131590Srgrimes	CORE_ADDR bufp;
2141590Srgrimes	int size, rseq, wseq;
2151590Srgrimes	char c;
2161590Srgrimes
2171590Srgrimes	/*
2181590Srgrimes	 * Display the unread portion of the message buffer. This gives the
2191590Srgrimes	 * user a some initial data to work from.
2201590Srgrimes	 */
2211590Srgrimes	if (quiet)
22298771Sjmallett		return;
22398771Sjmallett	bufp = kgdb_parse("msgbufp->msg_ptr");
2241590Srgrimes	size = (int)kgdb_parse("msgbufp->msg_size");
2251590Srgrimes	if (bufp == 0 || size == 0)
2261590Srgrimes		return;
2271590Srgrimes	rseq = (int)kgdb_parse("msgbufp->msg_rseq");
2281590Srgrimes	wseq = (int)kgdb_parse("msgbufp->msg_wseq");
2291590Srgrimes	rseq = MSGBUF_SEQ_TO_POS(size, rseq);
2301590Srgrimes	wseq = MSGBUF_SEQ_TO_POS(size, wseq);
2311590Srgrimes	if (rseq == wseq)
2321590Srgrimes		return;
2331590Srgrimes
2341590Srgrimes	printf("\nUnread portion of the kernel message buffer:\n");
235228992Suqs	while (rseq < wseq) {
2361590Srgrimes		read_memory(bufp + rseq, &c, 1);
2371590Srgrimes		putchar(c);
2381590Srgrimes		rseq++;
2391590Srgrimes		if (rseq == size)
2401590Srgrimes			rseq = 0;
2411590Srgrimes	}
2421590Srgrimes	if (c != '\n')
2431590Srgrimes		putchar('\n');
2441590Srgrimes	putchar('\n');
24548566Sbillf}
2461590Srgrimes
2471590Srgrimesstatic void
2481590Srgrimeskgdb_init(char *argv0 __unused)
2491590Srgrimes{
25048566Sbillf
2511590Srgrimes	parse_gdberr = mem_fileopen();
2521590Srgrimes	set_prompt("(kgdb) ");
2531590Srgrimes	initialize_kgdb_target();
2541590Srgrimes	initialize_kld_target();
2551590Srgrimes	kgdb_new_objfile_chain = target_new_objfile_hook;
2561590Srgrimes	target_new_objfile_hook = kgdb_new_objfile;
25785632Sschweikh}
2581590Srgrimes
2591590Srgrimes/*
2601590Srgrimes * Remote targets can support any number of syntaxes and we want to
2611590Srgrimes * support them all with one addition: we support specifying a device
2621590Srgrimes * node for a serial device without the "/dev/" prefix.
2631590Srgrimes *
2641590Srgrimes * What we do is to stat(2) the existing remote target first.  If that
2651590Srgrimes * fails, we try it with "/dev/" prepended.  If that succeeds we use
2661590Srgrimes * the resulting path, otherwise we use the original target.  If
2671590Srgrimes * either stat(2) succeeds make sure the file is either a character
2681590Srgrimes * device or a FIFO.
2691590Srgrimes */
2701590Srgrimesstatic void
2711590Srgrimesverify_remote(void)
2721590Srgrimes{
2731590Srgrimes	char path[PATH_MAX];
2741590Srgrimes	struct stat st;
2751590Srgrimes
2761590Srgrimes	if (stat(remote, &st) != 0) {
2771590Srgrimes		snprintf(path, sizeof(path), "/dev/%s", remote);
2781590Srgrimes		if (stat(path, &st) != 0)
2791590Srgrimes			return;
2801590Srgrimes		free(remote);
2811590Srgrimes		remote = strdup(path);
2821590Srgrimes	}
2831590Srgrimes	if (!S_ISCHR(st.st_mode) && !S_ISFIFO(st.st_mode))
2841590Srgrimes		errx(1, "%s: not a special file, FIFO or socket", remote);
2851590Srgrimes}
2861590Srgrimes
2871590Srgrimesstatic void
2881590Srgrimesadd_arg(struct captured_main_args *args, char *arg)
2891590Srgrimes{
2901590Srgrimes
29185632Sschweikh	args->argc++;
29285632Sschweikh	args->argv = reallocf(args->argv, (args->argc + 1) * sizeof(char *));
2931590Srgrimes	if (args->argv == NULL)
29498771Sjmallett		err(1, "Out of memory building argument list");
2951590Srgrimes	args->argv[args->argc] = arg;
2961590Srgrimes}
2971590Srgrimes
298125736Sbdeint
299125736Sbdemain(int argc, char *argv[])
3001590Srgrimes{
30198771Sjmallett	char path[PATH_MAX];
30298771Sjmallett	struct stat st;
3031590Srgrimes	struct captured_main_args args;
3041590Srgrimes	char *s;
3051590Srgrimes	int a, ch;
3061590Srgrimes
3071590Srgrimes	dumpnr = -1;
3081590Srgrimes
3091590Srgrimes	strlcpy(crashdir, "/var/crash", sizeof(crashdir));
3101590Srgrimes	s = getenv("KGDB_CRASH_DIR");
3111590Srgrimes	if (s != NULL)
3121590Srgrimes		strlcpy(crashdir, s, sizeof(crashdir));
3131590Srgrimes
3141590Srgrimes	/* Convert long options into short options. */
3151590Srgrimes	for (a = 1; a < argc; a++) {
3161590Srgrimes		s = argv[a];
3171590Srgrimes		if (s[0] == '-') {
31885632Sschweikh			s++;
31985632Sschweikh			/* Long options take either 1 or 2 dashes. */
3201590Srgrimes			if (s[0] == '-')
3211590Srgrimes				s++;
3221590Srgrimes			if (strcmp(s, "quiet") == 0)
3231590Srgrimes				argv[a] = "-q";
3241590Srgrimes			else if (strcmp(s, "fullname") == 0)
3251590Srgrimes				argv[a] = "-f";
3261590Srgrimes		}
3271590Srgrimes	}
3281590Srgrimes
3291590Srgrimes	quiet = 0;
3308874Srgrimes	memset (&args, 0, sizeof args);
3311590Srgrimes	args.use_windows = 0;
3328874Srgrimes	args.interpreter_p = INTERP_CONSOLE;
3338874Srgrimes	args.argv = malloc(sizeof(char *));
3341590Srgrimes	args.argv[0] = argv[0];
3358874Srgrimes
3361590Srgrimes	while ((ch = getopt(argc, argv, "ab:c:d:fn:qr:vw")) != -1) {
3378874Srgrimes		switch (ch) {
3381590Srgrimes		case 'a':
3391590Srgrimes			annotation_level++;
3401590Srgrimes			break;
3418874Srgrimes		case 'b':
3421590Srgrimes			{
34385632Sschweikh				int i;
34485632Sschweikh				char *p;
3451590Srgrimes
34698771Sjmallett				i = strtol (optarg, &p, 0);
34798771Sjmallett				if (i == 0 && p == optarg)
34898771Sjmallett				warnx("warning: could not set baud rate to `%s'.\n",
3491590Srgrimes				    optarg);
3501590Srgrimes				else
3511590Srgrimes					baud_rate = i;
3521590Srgrimes			}
3531590Srgrimes			break;
3541590Srgrimes		case 'c':	/* use given core file. */
3551590Srgrimes			if (vmcore != NULL) {
3561590Srgrimes				warnx("option %c: can only be specified once",
3571590Srgrimes				    optopt);
3581590Srgrimes				usage();
3591590Srgrimes				/* NOTREACHED */
36098771Sjmallett			}
36198771Sjmallett			vmcore = strdup(optarg);
36285632Sschweikh			break;
363116390Scharnier		case 'd':	/* lookup dumps in given directory. */
364116390Scharnier			strlcpy(crashdir, optarg, sizeof(crashdir));
3651590Srgrimes			break;
3661590Srgrimes		case 'f':
3671590Srgrimes			annotation_level = 1;
3681590Srgrimes			break;
3691590Srgrimes		case 'n':	/* use dump with given number. */
3701590Srgrimes			dumpnr = strtol(optarg, &s, 0);
3711590Srgrimes			if (dumpnr < 0 || *s != '\0') {
3721590Srgrimes				warnx("option %c: invalid kernel dump number",
3731590Srgrimes				    optopt);
3741590Srgrimes				usage();
3751590Srgrimes				/* NOTREACHED */
3761590Srgrimes			}
3771590Srgrimes			break;
3781590Srgrimes		case 'q':
3791590Srgrimes			quiet = 1;
3801590Srgrimes			add_arg(&args, "-q");
3811590Srgrimes			break;
3821590Srgrimes		case 'r':	/* use given device for remote session. */
3831590Srgrimes			if (remote != NULL) {
3841590Srgrimes				warnx("option %c: can only be specified once",
3851590Srgrimes				    optopt);
3861590Srgrimes				usage();
3871590Srgrimes				/* NOTREACHED */
3881590Srgrimes			}
3891590Srgrimes			remote = strdup(optarg);
3901590Srgrimes			break;
3911590Srgrimes		case 'v':	/* increase verbosity. */
3921590Srgrimes			verbose++;
3931590Srgrimes			break;
3941590Srgrimes		case 'w':	/* core file is writeable. */
3951590Srgrimes			add_arg(&args, "--write");
3961590Srgrimes			break;
3971590Srgrimes		case '?':
3981590Srgrimes		default:
3991590Srgrimes			usage();
40085632Sschweikh		}
4011590Srgrimes	}
4021590Srgrimes
4031590Srgrimes	if (((vmcore != NULL) ? 1 : 0) + ((dumpnr >= 0) ? 1 : 0) +
4041590Srgrimes	    ((remote != NULL) ? 1 : 0) > 1) {
40585632Sschweikh		warnx("options -c, -n and -r are mutually exclusive");
4061590Srgrimes		usage();
4071590Srgrimes		/* NOTREACHED */
4081590Srgrimes	}
4091590Srgrimes
4101590Srgrimes	if (verbose > 1)
4111590Srgrimes		warnx("using %s as the crash directory", crashdir);
4121590Srgrimes
4131590Srgrimes	if (argc > optind)
4141590Srgrimes		kernel = strdup(argv[optind++]);
4151590Srgrimes
4161590Srgrimes	if (argc > optind && (dumpnr >= 0 || remote != NULL)) {
4171590Srgrimes		warnx("options -n and -r do not take a core file. Ignored");
4181590Srgrimes		optind = argc;
4191590Srgrimes	}
4201590Srgrimes
4211590Srgrimes	if (dumpnr >= 0) {
4221590Srgrimes		snprintf(path, sizeof(path), "%s/vmcore.%d", crashdir, dumpnr);
4231590Srgrimes		if (stat(path, &st) == -1)
4241590Srgrimes			err(1, "%s", path);
4251590Srgrimes		if (!S_ISREG(st.st_mode))
4261590Srgrimes			errx(1, "%s: not a regular file", path);
4271590Srgrimes		vmcore = strdup(path);
4281590Srgrimes	} else if (remote != NULL) {
4291590Srgrimes		verify_remote();
4301590Srgrimes	} else if (argc > optind) {
4311590Srgrimes		if (vmcore == NULL)
4328874Srgrimes			vmcore = strdup(argv[optind++]);
4331590Srgrimes		if (argc > optind)
4348874Srgrimes			warnx("multiple core files specified. Ignored");
4358874Srgrimes	} else if (vmcore == NULL && kernel == NULL) {
4361590Srgrimes		vmcore = strdup(_PATH_MEM);
4378874Srgrimes		kernel = strdup(getbootfile());
4381590Srgrimes	}
4391590Srgrimes
4408874Srgrimes	if (verbose) {
4411590Srgrimes		if (vmcore != NULL)
4428874Srgrimes			warnx("core file: %s", vmcore);
4431590Srgrimes		if (remote != NULL)
4441590Srgrimes			warnx("device file: %s", remote);
4458874Srgrimes		if (kernel != NULL)
4461590Srgrimes			warnx("kernel image: %s", kernel);
4471590Srgrimes	}
4488874Srgrimes
4491590Srgrimes	/* A remote target requires an explicit kernel argument. */
4508874Srgrimes	if (remote != NULL && kernel == NULL) {
4511590Srgrimes		warnx("remote debugging requires a kernel");
4528874Srgrimes		usage();
4531590Srgrimes		/* NOTREACHED */
4548874Srgrimes	}
4551590Srgrimes
4568874Srgrimes	/* If we don't have a kernel image yet, try to find one. */
4571590Srgrimes	if (kernel == NULL) {
45885632Sschweikh		if (dumpnr >= 0)
45985632Sschweikh			kernel_from_dumpnr(dumpnr);
46085632Sschweikh
4611590Srgrimes		if (kernel == NULL)
4621590Srgrimes			errx(1, "couldn't find a suitable kernel image");
46385632Sschweikh		if (verbose)
46485632Sschweikh			warnx("kernel image: %s", kernel);
4651590Srgrimes	}
46698771Sjmallett	add_arg(&args, kernel);
46798771Sjmallett
4681590Srgrimes	if (vmcore != NULL)
4691590Srgrimes		add_arg(&args, vmcore);
4701590Srgrimes
4711590Srgrimes	/* The libgdb code uses optind too. Reset it... */
4721590Srgrimes	optind = 0;
4731590Srgrimes
4741590Srgrimes	/* Terminate argv list. */
475131184Sschweikh	add_arg(&args, NULL);
476131184Sschweikh
477131184Sschweikh	init_ui_hook = kgdb_init;
478131184Sschweikh
479131184Sschweikh	kgdb_sniffer_kluge = kgdb_trgt_trapframe_sniffer;
480131184Sschweikh
481131184Sschweikh	return (gdb_main(&args));
4821590Srgrimes}
4831590Srgrimes