Improve the usage. Without any arguments, kgdb(1) works on /dev/mem

with the currently running kernel image. Otherwise, one of -c, -n or
-r is expected for working on a particular core file (-c), working
on a saved dump (-n) or working remotely (-r). When working on a
saved dump, a kernel may be omitted.
For a remote debugging session (-r), kgdb(1) will use the specified
device.
This commit is contained in:
Marcel Moolenaar 2004-08-15 02:39:20 +00:00
parent 115e9ac656
commit 7a5bf37951
2 changed files with 127 additions and 50 deletions

View File

@ -33,7 +33,7 @@
.Nm
.Op Ar -v
.Op Ar -d crashdir
.Op Ar -n dumpnr
.Op Ar -c core | -n dumpnr | -r device
.Op Ar kernel [ Ar core ]
.Sh DESCRIPTION
The

View File

@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$");
#include <inttypes.h>
#include <kvm.h>
#include <limits.h>
#include <paths.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -69,6 +70,7 @@ static int verbose;
static char crashdir[PATH_MAX];
static char *kernel;
static char *remote;
static char *vmcore;
static void (*kgdb_new_objfile_chain)(struct objfile * objfile);
@ -76,14 +78,15 @@ static void (*kgdb_new_objfile_chain)(struct objfile * objfile);
static void
usage(void)
{
fprintf(stderr,
"usage: %s [-v] [-d crashdir] [-n dumpnr] [kernel [core]]\n",
getprogname());
"usage: %s [-v] [-d crashdir] [-c core | -n dumpnr | -r device]\n"
"\t[kernel [core]]\n", getprogname());
exit(1);
}
static void
use_dump(int nr)
kernel_from_dumpnr(int nr)
{
char path[PATH_MAX];
FILE *info;
@ -91,18 +94,11 @@ use_dump(int nr)
struct stat st;
int l;
snprintf(path, sizeof(path), "%s/vmcore.%d", crashdir, nr);
if (stat(path, &st) == -1)
err(1, path);
if (!S_ISREG(st.st_mode))
errx(1, "%s: not a regular file", path);
vmcore = strdup(path);
/*
* See if there's a kernel image right here, use it. The kernel
* image is either called kernel.<nr> or is in a subdirectory
* kernel.<nr> and called kernel.
* If there's a kernel image right here in the crash directory, then
* use it. The kernel image is either called kernel.<nr> or is in a
* subdirectory kernel.<nr> and called kernel. The latter allows us
* to collect the modules in the same place.
*/
snprintf(path, sizeof(path), "%s/kernel.%d", crashdir, nr);
if (stat(path, &st) == 0) {
@ -121,9 +117,11 @@ use_dump(int nr)
}
/*
* No kernel image here. Parse the dump header. The kernel object
* No kernel image here. Parse the dump header. The kernel object
* directory can be found there and we probably have the kernel
* image in it still.
* image still in it. The object directory may also have a kernel
* with debugging info (called kernel.debug). If we have a debug
* kernel, use it.
*/
snprintf(path, sizeof(path), "%s/info.%d", crashdir, nr);
info = fopen(path, "r");
@ -150,9 +148,6 @@ use_dump(int nr)
}
}
fclose(info);
if (verbose && kernel == NULL)
warnx("dump %d: no kernel found", nr);
}
static void
@ -176,9 +171,13 @@ kgdb_interp_command_loop(void *data)
static int once = 0;
if (!once) {
symbol_file_add_main (kernel, 0);
print_stack_frame(get_current_frame(), -1, 0);
once = 1;
symbol_file_add_main (kernel, 0);
if (remote)
push_remote_target (remote, 0);
else
kgdb_target();
print_stack_frame(get_current_frame(), -1, 0);
}
command_loop();
}
@ -199,7 +198,6 @@ kgdb_init(char *argv0 __unused)
interp_add(kgdb);
set_prompt("(kgdb) ");
kgdb_target();
kgdb_new_objfile_chain = target_new_objfile_hook;
target_new_objfile_hook = kgdb_new_objfile;
}
@ -207,6 +205,8 @@ kgdb_init(char *argv0 __unused)
int
main(int argc, char *argv[])
{
char path[PATH_MAX];
struct stat st;
struct captured_main_args args;
char *s;
int ch;
@ -218,12 +218,21 @@ main(int argc, char *argv[])
if (s != NULL)
strlcpy(crashdir, s, sizeof(crashdir));
while ((ch = getopt(argc, argv, "d:n:v")) != -1) {
while ((ch = getopt(argc, argv, "c:d:n:r:v")) != -1) {
switch (ch) {
case 'd':
case 'c': /* use given core file. */
if (vmcore != NULL) {
warnx("option %c: can only be specified once",
optopt);
usage();
/* NOTREACHED */
}
vmcore = strdup(optarg);
break;
case 'd': /* lookup dumps in given directory. */
strlcpy(crashdir, optarg, sizeof(crashdir));
break;
case 'n':
case 'n': /* use dump with given number. */
dumpnr = strtol(optarg, &s, 0);
if (dumpnr < 0 || *s != '\0') {
warnx("option %c: invalid kernel dump number",
@ -232,7 +241,16 @@ main(int argc, char *argv[])
/* NOTREACHED */
}
break;
case 'v':
case 'r': /* use given device for remote session. */
if (remote != NULL) {
warnx("option %c: can only be specified once",
optopt);
usage();
/* NOTREACHED */
}
remote = strdup(optarg);
break;
case 'v': /* increase verbosity. */
verbose++;
break;
case '?':
@ -241,40 +259,99 @@ main(int argc, char *argv[])
}
}
if (((vmcore != NULL) ? 1 : 0) + ((dumpnr >= 0) ? 1 : 0) +
((remote != NULL) ? 1 : 0) > 1) {
warnx("options -c, -n and -r are mutually exclusive");
usage();
/* NOTREACHED */
}
if (verbose > 1)
warnx("using %s as the crash directory", crashdir);
if (dumpnr >= 0)
use_dump(dumpnr);
if (argc > optind) {
if (kernel != NULL)
free(kernel);
if (argc > optind)
kernel = strdup(argv[optind++]);
}
while (argc > optind) {
if (vmcore != NULL)
errx(1, "multiple core files specified");
vmcore = strdup(argv[optind++]);
if (argc > optind && (dumpnr >= 0 || remote != NULL)) {
warnx("options -n and -r do not take a core file. Ignored");
optind = argc;
}
if (kernel == NULL)
errx(1, "kernel not specified");
if (vmcore == NULL)
errx(1, "core file not specified");
if (dumpnr >= 0) {
snprintf(path, sizeof(path), "%s/vmcore.%d", crashdir, dumpnr);
if (stat(path, &st) == -1)
err(1, path);
if (!S_ISREG(st.st_mode))
errx(1, "%s: not a regular file", path);
vmcore = strdup(path);
} else if (remote != NULL) {
if (stat(remote, &st) != 0) {
snprintf(path, sizeof(path), "/dev/%s", remote);
if (stat(path, &st) != 0) {
err(1, "%s", remote);
/* NOTREACHED */
}
free(remote);
remote = strdup(path);
}
if (!S_ISCHR(st.st_mode) && !S_ISFIFO(st.st_mode)) {
errx(1, "%s: not a special file, FIFO or socket",
remote);
/* NOTREACHED */
}
} else if (argc > optind) {
if (vmcore == NULL)
vmcore = strdup(argv[optind++]);
if (argc > optind)
warnx("multiple core files specified. Ignored");
} else if (vmcore == NULL && kernel == NULL) {
vmcore = strdup(_PATH_MEM);
kernel = strdup(getbootfile());
}
if (verbose) {
warnx("kernel image: %s", kernel);
warnx("core file: %s", vmcore);
if (vmcore != NULL)
warnx("core file: %s", vmcore);
if (remote != NULL)
warnx("device file: %s", remote);
if (kernel != NULL)
warnx("kernel image: %s", kernel);
}
s = malloc(_POSIX2_LINE_MAX);
kvm = kvm_openfiles(kernel, vmcore, NULL, O_RDONLY, s);
if (kvm == NULL)
errx(1, s);
free(s);
/*
* At this point we must either have a core file or have a kernel
* with a remote target.
*/
if (remote != NULL && kernel == NULL) {
warnx("remote debugging requires a kernel");
usage();
/* NOTREACHED */
}
if (vmcore == NULL && remote == NULL) {
warnx("need a core file or a device for remote debugging");
usage();
/* NOTREACHED */
}
kgdb_thr_init();
/* If we don't have a kernel image yet, try to find one. */
if (kernel == NULL) {
if (dumpnr >= 0)
kernel_from_dumpnr(dumpnr);
if (kernel == NULL)
errx(1, "couldn't find a suitable kernel image");
if (verbose)
warnx("kernel image: %s", kernel);
}
if (remote == NULL) {
s = malloc(_POSIX2_LINE_MAX);
kvm = kvm_openfiles(kernel, vmcore, NULL, O_RDONLY, s);
if (kvm == NULL)
errx(1, s);
free(s);
kgdb_thr_init();
}
memset (&args, 0, sizeof args);
args.argc = 1;