summaryrefslogtreecommitdiffstats
path: root/gnu/usr.bin/gdb/kgdb/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/usr.bin/gdb/kgdb/main.c')
-rw-r--r--gnu/usr.bin/gdb/kgdb/main.c173
1 files changed, 125 insertions, 48 deletions
diff --git a/gnu/usr.bin/gdb/kgdb/main.c b/gnu/usr.bin/gdb/kgdb/main.c
index 6204c0b..3209fc9 100644
--- a/gnu/usr.bin/gdb/kgdb/main.c
+++ b/gnu/usr.bin/gdb/kgdb/main.c
@@ -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) {
+ 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);
- once = 1;
}
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);
+ }
+
+ /*
+ * 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 */
}
- s = malloc(_POSIX2_LINE_MAX);
- kvm = kvm_openfiles(kernel, vmcore, NULL, O_RDONLY, s);
- if (kvm == NULL)
- errx(1, s);
- free(s);
+ /* If we don't have a kernel image yet, try to find one. */
+ if (kernel == NULL) {
+ if (dumpnr >= 0)
+ kernel_from_dumpnr(dumpnr);
- kgdb_thr_init();
+ 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;
OpenPOWER on IntegriCloud