main.c revision 142151
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 142151 2005-02-20 22:55:07Z kan $");
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 <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
64extern void symbol_file_add_main (char *args, int from_tty);
65
66#include "kgdb.h"
67
68kvm_t *kvm;
69
70static int dumpnr;
71static int verbose;
72
73static char crashdir[PATH_MAX];
74static char *kernel;
75static char *remote;
76static char *vmcore;
77
78static void (*kgdb_new_objfile_chain)(struct objfile * objfile);
79
80static void
81usage(void)
82{
83
84	fprintf(stderr,
85	    "usage: %s [-a] [-v] [-d crashdir] [-c core | -n dumpnr | -r device]\n"
86	    "\t[kernel [core]]\n", getprogname());
87	exit(1);
88}
89
90static void
91kernel_from_dumpnr(int nr)
92{
93	char path[PATH_MAX];
94	FILE *info;
95	char *s;
96	struct stat st;
97	int l;
98
99	/*
100	 * If there's a kernel image right here in the crash directory, then
101	 * use it.  The kernel image is either called kernel.<nr> or is in a
102	 * subdirectory kernel.<nr> and called kernel.  The latter allows us
103	 * to collect the modules in the same place.
104	 */
105	snprintf(path, sizeof(path), "%s/kernel.%d", crashdir, nr);
106	if (stat(path, &st) == 0) {
107		if (S_ISREG(st.st_mode)) {
108			kernel = strdup(path);
109			return;
110		}
111		if (S_ISDIR(st.st_mode)) {
112			snprintf(path, sizeof(path), "%s/kernel.%d/kernel",
113			    crashdir, nr);
114			if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) {
115				kernel = strdup(path);
116				return;
117			}
118		}
119	}
120
121	/*
122	 * No kernel image here.  Parse the dump header.  The kernel object
123	 * directory can be found there and we probably have the kernel
124	 * image still in it.  The object directory may also have a kernel
125	 * with debugging info (called kernel.debug).  If we have a debug
126	 * kernel, use it.
127	 */
128	snprintf(path, sizeof(path), "%s/info.%d", crashdir, nr);
129	info = fopen(path, "r");
130	if (info == NULL) {
131		warn(path);
132		return;
133	}
134	while (fgets(path, sizeof(path), info) != NULL) {
135		l = strlen(path);
136		if (l > 0 && path[l - 1] == '\n')
137			path[--l] = '\0';
138		if (strncmp(path, "    ", 4) == 0) {
139			s = strchr(path, ':');
140			s = (s == NULL) ? path + 4 : s + 1;
141			l = snprintf(path, sizeof(path), "%s/kernel.debug", s);
142			if (stat(path, &st) == -1 || !S_ISREG(st.st_mode)) {
143				path[l - 6] = '\0';
144				if (stat(path, &st) == -1 ||
145				    !S_ISREG(st.st_mode))
146					break;
147			}
148			kernel = strdup(path);
149			break;
150		}
151	}
152	fclose(info);
153}
154
155static void
156kgdb_new_objfile(struct objfile *objfile)
157{
158#if 0
159	printf("XXX: %s(%p)\n", __func__, objfile);
160	if (objfile != NULL) {
161		goto out;
162	}
163
164out:
165#endif
166	if (kgdb_new_objfile_chain != NULL)
167		kgdb_new_objfile_chain(objfile);
168}
169
170static void
171kgdb_init_target(void)
172{
173	bfd *kern_bfd;
174	int kern_desc;
175
176	kern_desc = open(kernel, O_RDONLY);
177	if (kern_desc == -1)
178		errx(1, "couldn't open a kernel image");
179
180	kern_bfd = bfd_fdopenr(kernel, gnutarget, kern_desc);
181	if (kern_bfd == NULL) {
182		close(kern_desc);
183		errx(1, "\"%s\": can't open to probe ABI: %s.", kernel,
184			bfd_errmsg (bfd_get_error ()));
185	}
186	bfd_set_cacheable(kern_bfd, 1);
187
188	if (!bfd_check_format (kern_bfd, bfd_object)) {
189		bfd_close(kern_bfd);
190		errx(1, "\"%s\": not in executable format: %s", kernel,
191			bfd_errmsg(bfd_get_error()));
192        }
193
194	set_gdbarch_from_file (kern_bfd);
195	bfd_close(kern_bfd);
196
197	symbol_file_add_main (kernel, 0);
198	if (remote)
199		push_remote_target (remote, 0);
200	else
201		kgdb_target();
202}
203
204static void
205kgdb_interp_command_loop(void *data)
206{
207	static int once = 0;
208
209	if (!once) {
210		once = 1;
211		kgdb_init_target();
212		kgdb_target();
213		print_stack_frame (get_selected_frame (),
214                	frame_relative_level (get_selected_frame ()), 1);
215	}
216	command_loop();
217}
218
219static void
220kgdb_init(char *argv0 __unused)
221{
222	static struct interp_procs procs = {
223		NULL,
224		NULL,
225		NULL,
226		NULL,
227		NULL,
228		kgdb_interp_command_loop
229	};
230	struct interp *kgdb;
231	kgdb = interp_new("kgdb", NULL, cli_out_new(gdb_stdout), &procs);
232	interp_add(kgdb);
233
234	set_prompt("(kgdb) ");
235	kgdb_new_objfile_chain = target_new_objfile_hook;
236	target_new_objfile_hook = kgdb_new_objfile;
237}
238
239int
240main(int argc, char *argv[])
241{
242	char path[PATH_MAX];
243	struct stat st;
244	struct captured_main_args args;
245	char *s;
246	int ch;
247
248	dumpnr = -1;
249
250	strlcpy(crashdir, "/var/crash", sizeof(crashdir));
251	s = getenv("KGDB_CRASH_DIR");
252	if (s != NULL)
253		strlcpy(crashdir, s, sizeof(crashdir));
254
255	while ((ch = getopt(argc, argv, "ac:d:n:r:v")) != -1) {
256		switch (ch) {
257		case 'a':
258			annotation_level++;
259			break;
260		case 'c':	/* use given core file. */
261			if (vmcore != NULL) {
262				warnx("option %c: can only be specified once",
263				    optopt);
264				usage();
265				/* NOTREACHED */
266			}
267			vmcore = strdup(optarg);
268			break;
269		case 'd':	/* lookup dumps in given directory. */
270			strlcpy(crashdir, optarg, sizeof(crashdir));
271			break;
272		case 'n':	/* use dump with given number. */
273			dumpnr = strtol(optarg, &s, 0);
274			if (dumpnr < 0 || *s != '\0') {
275				warnx("option %c: invalid kernel dump number",
276				    optopt);
277				usage();
278				/* NOTREACHED */
279			}
280			break;
281		case 'r':	/* use given device for remote session. */
282			if (remote != NULL) {
283				warnx("option %c: can only be specified once",
284				    optopt);
285				usage();
286				/* NOTREACHED */
287			}
288			remote = strdup(optarg);
289			break;
290		case 'v':	/* increase verbosity. */
291			verbose++;
292			break;
293		case '?':
294		default:
295			usage();
296		}
297	}
298
299	if (((vmcore != NULL) ? 1 : 0) + ((dumpnr >= 0) ? 1 : 0) +
300	    ((remote != NULL) ? 1 : 0) > 1) {
301		warnx("options -c, -n and -r are mutually exclusive");
302		usage();
303		/* NOTREACHED */
304	}
305
306	if (verbose > 1)
307		warnx("using %s as the crash directory", crashdir);
308
309	if (argc > optind)
310		kernel = strdup(argv[optind++]);
311
312	if (argc > optind && (dumpnr >= 0 || remote != NULL)) {
313		warnx("options -n and -r do not take a core file. Ignored");
314		optind = argc;
315	}
316
317	if (dumpnr >= 0) {
318		snprintf(path, sizeof(path), "%s/vmcore.%d", crashdir, dumpnr);
319		if (stat(path, &st) == -1)
320			err(1, path);
321		if (!S_ISREG(st.st_mode))
322			errx(1, "%s: not a regular file", path);
323		vmcore = strdup(path);
324	} else if (remote != NULL && remote[0] != ':' && remote[0] != '|') {
325		if (stat(remote, &st) != 0) {
326			snprintf(path, sizeof(path), "/dev/%s", remote);
327			if (stat(path, &st) != 0) {
328				err(1, "%s", remote);
329				/* NOTREACHED */
330			}
331			free(remote);
332			remote = strdup(path);
333		}
334		if (!S_ISCHR(st.st_mode) && !S_ISFIFO(st.st_mode)) {
335			errx(1, "%s: not a special file, FIFO or socket",
336			    remote);
337			/* NOTREACHED */
338		}
339	} else if (argc > optind) {
340		if (vmcore == NULL)
341			vmcore = strdup(argv[optind++]);
342		if (argc > optind)
343			warnx("multiple core files specified. Ignored");
344	} else if (vmcore == NULL && kernel == NULL) {
345		vmcore = strdup(_PATH_MEM);
346		kernel = strdup(getbootfile());
347	}
348
349	if (verbose) {
350		if (vmcore != NULL)
351			warnx("core file: %s", vmcore);
352		if (remote != NULL)
353			warnx("device file: %s", remote);
354		if (kernel != NULL)
355			warnx("kernel image: %s", kernel);
356	}
357
358	/*
359	 * At this point we must either have a core file or have a kernel
360	 * with a remote target.
361	 */
362	if (remote != NULL && kernel == NULL) {
363		warnx("remote debugging requires a kernel");
364		usage();
365		/* NOTREACHED */
366	}
367	if (vmcore == NULL && remote == NULL) {
368		warnx("need a core file or a device for remote debugging");
369		usage();
370		/* NOTREACHED */
371	}
372
373	/* If we don't have a kernel image yet, try to find one. */
374	if (kernel == NULL) {
375		if (dumpnr >= 0)
376			kernel_from_dumpnr(dumpnr);
377
378		if (kernel == NULL)
379			errx(1, "couldn't find a suitable kernel image");
380		if (verbose)
381			warnx("kernel image: %s", kernel);
382	}
383
384	if (remote == NULL) {
385		s = malloc(_POSIX2_LINE_MAX);
386		kvm = kvm_openfiles(kernel, vmcore, NULL, O_RDONLY, s);
387		if (kvm == NULL)
388			errx(1, s);
389		free(s);
390		kgdb_thr_init();
391	}
392
393	memset (&args, 0, sizeof args);
394	args.argc = 1;
395	args.argv = argv;
396	args.use_windows = 0;
397	args.interpreter_p = "kgdb";
398
399	init_ui_hook = kgdb_init;
400
401	return (gdb_main(&args));
402}
403