main.c revision 147570
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 147570 2005-06-24 00:50:12Z peter $");
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 [-afqv] [-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 a, ch, quiet;
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	/* Convert long options into short options. */
256	for (a = 1; a < argc; a++) {
257		s = argv[a];
258		if (s[0] == '-') {
259			s++;
260			/* Long options take either 1 or 2 dashes. */
261			if (s[0] == '-')
262				s++;
263			if (strcmp(s, "quiet") == 0)
264				argv[a] = "-q";
265			else if (strcmp(s, "fullname") == 0)
266				argv[a] = "-f";
267		}
268	}
269
270	quiet = 0;
271
272	while ((ch = getopt(argc, argv, "ac:d:fn:qr:v")) != -1) {
273		switch (ch) {
274		case 'a':
275			annotation_level++;
276			break;
277		case 'c':	/* use given core file. */
278			if (vmcore != NULL) {
279				warnx("option %c: can only be specified once",
280				    optopt);
281				usage();
282				/* NOTREACHED */
283			}
284			vmcore = strdup(optarg);
285			break;
286		case 'd':	/* lookup dumps in given directory. */
287			strlcpy(crashdir, optarg, sizeof(crashdir));
288			break;
289		case 'f':
290			annotation_level = 1;
291			break;
292		case 'n':	/* use dump with given number. */
293			dumpnr = strtol(optarg, &s, 0);
294			if (dumpnr < 0 || *s != '\0') {
295				warnx("option %c: invalid kernel dump number",
296				    optopt);
297				usage();
298				/* NOTREACHED */
299			}
300			break;
301		case 'q':
302			quiet = 1;
303			break;
304		case 'r':	/* use given device for remote session. */
305			if (remote != NULL) {
306				warnx("option %c: can only be specified once",
307				    optopt);
308				usage();
309				/* NOTREACHED */
310			}
311			remote = strdup(optarg);
312			break;
313		case 'v':	/* increase verbosity. */
314			verbose++;
315			break;
316		case '?':
317		default:
318			usage();
319		}
320	}
321
322	if (((vmcore != NULL) ? 1 : 0) + ((dumpnr >= 0) ? 1 : 0) +
323	    ((remote != NULL) ? 1 : 0) > 1) {
324		warnx("options -c, -n and -r are mutually exclusive");
325		usage();
326		/* NOTREACHED */
327	}
328
329	if (verbose > 1)
330		warnx("using %s as the crash directory", crashdir);
331
332	if (argc > optind)
333		kernel = strdup(argv[optind++]);
334
335	if (argc > optind && (dumpnr >= 0 || remote != NULL)) {
336		warnx("options -n and -r do not take a core file. Ignored");
337		optind = argc;
338	}
339
340	if (dumpnr >= 0) {
341		snprintf(path, sizeof(path), "%s/vmcore.%d", crashdir, dumpnr);
342		if (stat(path, &st) == -1)
343			err(1, path);
344		if (!S_ISREG(st.st_mode))
345			errx(1, "%s: not a regular file", path);
346		vmcore = strdup(path);
347	} else if (remote != NULL && remote[0] != ':' && remote[0] != '|') {
348		if (stat(remote, &st) != 0) {
349			snprintf(path, sizeof(path), "/dev/%s", remote);
350			if (stat(path, &st) != 0) {
351				err(1, "%s", remote);
352				/* NOTREACHED */
353			}
354			free(remote);
355			remote = strdup(path);
356		}
357		if (!S_ISCHR(st.st_mode) && !S_ISFIFO(st.st_mode)) {
358			errx(1, "%s: not a special file, FIFO or socket",
359			    remote);
360			/* NOTREACHED */
361		}
362	} else if (argc > optind) {
363		if (vmcore == NULL)
364			vmcore = strdup(argv[optind++]);
365		if (argc > optind)
366			warnx("multiple core files specified. Ignored");
367	} else if (vmcore == NULL && kernel == NULL) {
368		vmcore = strdup(_PATH_MEM);
369		kernel = strdup(getbootfile());
370	}
371
372	if (verbose) {
373		if (vmcore != NULL)
374			warnx("core file: %s", vmcore);
375		if (remote != NULL)
376			warnx("device file: %s", remote);
377		if (kernel != NULL)
378			warnx("kernel image: %s", kernel);
379	}
380
381	/*
382	 * At this point we must either have a core file or have a kernel
383	 * with a remote target.
384	 */
385	if (remote != NULL && kernel == NULL) {
386		warnx("remote debugging requires a kernel");
387		usage();
388		/* NOTREACHED */
389	}
390	if (vmcore == NULL && remote == NULL) {
391		warnx("need a core file or a device for remote debugging");
392		usage();
393		/* NOTREACHED */
394	}
395
396	/* If we don't have a kernel image yet, try to find one. */
397	if (kernel == NULL) {
398		if (dumpnr >= 0)
399			kernel_from_dumpnr(dumpnr);
400
401		if (kernel == NULL)
402			errx(1, "couldn't find a suitable kernel image");
403		if (verbose)
404			warnx("kernel image: %s", kernel);
405	}
406
407	if (remote == NULL) {
408		s = malloc(_POSIX2_LINE_MAX);
409		kvm = kvm_openfiles(kernel, vmcore, NULL, O_RDONLY, s);
410		if (kvm == NULL)
411			errx(1, s);
412		kgdb_thr_init();
413	}
414
415	/* The libgdb code uses optind too. Reset it... */
416	optind = 0;
417
418	memset (&args, 0, sizeof args);
419	args.argv = argv;
420	args.argc = 1 + quiet;
421	if (quiet)
422		argv[1] = "-q";
423	argv[args.argc] = NULL;
424	args.use_windows = 0;
425	args.interpreter_p = "kgdb";
426
427	init_ui_hook = kgdb_init;
428
429	return (gdb_main(&args));
430}
431