Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 11 Jun 2004 05:58:36 GMT
From:      Marcel Moolenaar <marcel@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 54621 for review
Message-ID:  <200406110558.i5B5waNX027918@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=54621

Change 54621 by marcel@marcel_nfs on 2004/06/11 05:57:42

	o  Add kthr.c. It will contain kernel thread support functions.
	   The functions are dummies for now.
	o  Handle the gdb packets. This is mostly untested, but taken
	   from the kernel which is known to work.
	o  Add command line processing:
	   +  Add option -n, which takes an integer and instructs kgdb
	      to open /var/crash/vmcore.<n> and parse /var/crash/info.<n>
	      for the corresponding kernel. If kernel.debug exists, it
	      is used. Otherwise kernel is used. If no kernel is found,
	      the user has to enter the kernel file name explicitly.
	   +  Accept [kernel [core]]. If -n has been given, kernel takes
	      precedence and core cannot be given directly.

Affected files ...

.. //depot/projects/gdb/usr.bin/kgdb/Makefile#5 edit
.. //depot/projects/gdb/usr.bin/kgdb/kgdb.h#2 edit
.. //depot/projects/gdb/usr.bin/kgdb/kthr.c#1 add
.. //depot/projects/gdb/usr.bin/kgdb/main.c#6 edit
.. //depot/projects/gdb/usr.bin/kgdb/md_i386.c#2 edit
.. //depot/projects/gdb/usr.bin/kgdb/packet.c#2 edit

Differences ...

==== //depot/projects/gdb/usr.bin/kgdb/Makefile#5 (text+ko) ====

@@ -1,7 +1,7 @@
 # $FreeBSD$
 
 PROG=	kgdb
-SRCS=	main.c md_${MACHINE_ARCH}.c packet.c
+SRCS=	kthr.c main.c md_${MACHINE_ARCH}.c packet.c
 
 DPADD=	${LIBKVM} ${LIBUTIL}
 LDADD=	-lkvm -lutil

==== //depot/projects/gdb/usr.bin/kgdb/kgdb.h#2 (text+ko) ====

@@ -31,7 +31,6 @@
 extern size_t gdb_rxsz;
 extern char *gdb_txp;
 
-void gdb_packet(void);
 void gdb_packet_data(const char *, size_t);
 int gdb_packet_recv(char *, size_t);
 int gdb_packet_send(const char *, size_t);
@@ -108,9 +107,15 @@
 extern kvm_t *kvm;
 
 struct kthr {
-	void *frame;
+	void	*td_frame;
+	int	td_tid;
 };
 
 extern struct kthr *curkthr;
 
+struct kthr *kgdb_thr_first(void);
+struct kthr *kgdb_thr_lookup(int);
+struct kthr *kgdb_thr_next(struct kthr *);
+struct kthr *kgdb_thr_select(struct kthr *);
+
 #endif /* _KGDB_H_ */

==== //depot/projects/gdb/usr.bin/kgdb/main.c#6 (text+ko) ====

@@ -27,6 +27,8 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
+#include <sys/param.h>
+#include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/ioctl.h>
 #include <sys/resource.h>
@@ -54,8 +56,11 @@
 char *gdb_rp_dev;
 pid_t gdb_pid;
 
+int dumpnr;
+char crashdir[PATH_MAX];
+char *kernel;
+char *vmcore;
 kvm_t *kvm;
-struct kthr *curkthr;
 
 char *cmdfile_name;
 int cmdfile_fd;
@@ -63,6 +68,14 @@
 static const char cmd_set_prompt[] = "set prompt (kgdb) \n";
 
 static void
+usage(void)
+{
+	fprintf(stderr, "usage: %s [-d dumpno] [kernel] [core]\n",
+	    getprogname());
+	exit(1);
+}
+
+static void
 atexit_unlink_cmdfile(void)
 {
 	close(cmdfile_fd);	/* Is likely closed already. */
@@ -93,19 +106,100 @@
 	return (write(gdb_rp_fd, p, sz));
 }
 
-void gdb_packet(void)
+static void
+parse_dump(void)
 {
-	printf("`%s'\n", gdb_rxp);
+	char path[PATH_MAX];
+	FILE *info;
+	char *s;
+	struct stat st;
+	int l;
+
+	snprintf(path, sizeof(path), "%s/vmcore.%d", crashdir, dumpnr);
+	if (stat(path, &st) == -1)
+		err(1, path);
+	vmcore = strdup(path);
+	snprintf(path, sizeof(path), "%s/info.%d", crashdir, dumpnr);
+	info = fopen(path, "r");
+	if (info == NULL) {
+		warn(path);
+		return;
+	}
+	while (fgets(path, sizeof(path), info) != NULL) {
+		l = strlen(path);
+		if (l > 0 && path[l - 1] == '\n')
+			path[--l] = '\0';
+		if (strncmp(path, "    ", 4) == 0) {
+			s = strchr(path, ':');
+			s = (s == NULL) ? path + 4 : s + 1;
+			l = snprintf(path, sizeof(path), "%s/kernel.debug", s);
+			if (stat(path, &st) == -1) {
+				path[l - 6] = '\0';
+				if (stat(path, &st) == -1)
+					break;
+			}
+			kernel = strdup(path);
+			break;
+		}
+	}
+	fclose(info);
 }
 
 int
-main(int argc __unused, char *argv[] __unused)
+main(int argc, char *argv[])
 {
 	char buf[256];
 	fd_set rfds, wfds, xfds;
+	char *s;
 	ssize_t sz;
 	int fdin, fdout;
 	int f, nfds, status;
+	int ch;
+
+	strcpy(crashdir, "/var/crash");
+	while ((ch = getopt(argc, argv, "n:")) != -1) {
+		switch (ch) {
+		case 'n':
+			if (dumpnr) {
+				warnx("option %c specified multiple times",
+				    optopt);
+				usage();
+				/* NOTREACHED */
+			}
+			dumpnr = strtol(optarg, &s, 0);
+			if (dumpnr == 0 || *s != '\0') {
+				warnx("option %c: invalid kernel dump number",
+				    optopt);
+				usage();
+				/* NOTREACHED */
+			}
+			parse_dump();
+			break;
+		case '?':
+		default:
+			usage();
+		}
+	}
+	argc -= optind;
+	argv += optind;
+
+	if (argc > 0) {
+		if (kernel != NULL)
+			free(kernel);
+		kernel = strdup(*argv++);
+		argc--;
+	}
+	while (argc > 0) {
+		if (vmcore != NULL)
+			errx(1, "multiple core files specified");
+		vmcore = strdup(*argv++);
+		argc--;
+	}
+
+	if (kernel == NULL)
+		errx(1, "kernel not specified");
+	if (vmcore == NULL)
+		errx(1, "core file not specified");
 
 	cmdfile_name = strdup("/tmp/kgdb.XXXXXXXX");
 	if (cmdfile_name == NULL)

==== //depot/projects/gdb/usr.bin/kgdb/md_i386.c#2 (text+ko) ====

@@ -44,7 +44,7 @@
 gdb_cpu_getreg(int regnum, size_t *regsz)
 {
 	static register_t synth;
-	struct trapframe *tf = curkthr->frame;
+	struct trapframe *tf = curkthr->td_frame;
 
 	*regsz = gdb_cpu_regsz(regnum);
 	switch (regnum) {
@@ -73,7 +73,7 @@
 void
 gdb_cpu_setreg(int regnum, register_t val)
 {
-	struct trapframe *tf = curkthr->frame;
+	struct trapframe *tf = curkthr->td_frame;
 
 	switch (regnum) {
 	case GDB_REG_PC: tf->tf_eip = val; break;

==== //depot/projects/gdb/usr.bin/kgdb/packet.c#2 (text+ko) ====

@@ -30,6 +30,7 @@
 #include <sys/types.h>
 #include <assert.h>
 #include <ctype.h>
+#include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
 #include <kvm.h>
@@ -53,6 +54,114 @@
 	    10 + (((c) < 'a') ? (c) - 'A' : (c) - 'a'))
 #define	N2C(n)	(((n) < 10) ? (n) + '0' : (n) + 'a' - 10)
 
+static void
+gdb_packet(void)
+{
+	struct kthr *thr_iter;
+
+	thr_iter = NULL;
+	printf("GDB: got '%s'\n", gdb_rxp);
+	switch (gdb_rx_char()) {
+	case '?':	/* Last signal. */
+		gdb_tx_begin('S');
+		gdb_tx_hex(gdb_cpu_signal(0, 0), 2);
+		gdb_tx_end();
+		break;
+	case 'g': {	/* Read registers. */
+		size_t r;
+		gdb_tx_begin(0);
+		for (r = 0; r < GDB_NREGS; r++)
+			gdb_tx_reg(r);
+		gdb_tx_end();
+		break;
+	}
+	case 'G':	/* Write registers. */
+		gdb_tx_err(0);
+		break;
+	case 'H': {	/* Set thread. */
+		intmax_t tid;
+		struct kthr *thr;
+		gdb_rx_char();
+		gdb_rx_varhex(&tid);
+		if (tid > 0) {
+			thr = kgdb_thr_lookup(tid);
+			if (thr == NULL) {
+				gdb_tx_err(ENOENT);
+				break;
+			}
+			kgdb_thr_select(thr);
+		}
+		gdb_tx_ok();
+		break;
+	}
+	case 'm': {	/* Read memory. */
+		uintmax_t addr, size;
+		if (gdb_rx_varhex(&addr) || gdb_rx_char() != ',' ||
+		    gdb_rx_varhex(&size)) {
+			gdb_tx_err(EINVAL);
+			break;
+		}
+		gdb_tx_begin(0);
+		gdb_tx_mem((char *)(uintptr_t)addr, size);
+		gdb_tx_end();
+		break;
+	}
+	case 'M':	/* Write memory. */
+		gdb_tx_err(0);
+		break;
+	case 'P': {	/* Write register. */
+		uintmax_t reg, val;
+		if (gdb_rx_varhex(&reg) || gdb_rx_char() != '=' ||
+		    gdb_rx_varhex(&val)) {
+			gdb_tx_err(EINVAL);
+			break;
+		}
+		gdb_cpu_setreg(reg, val);
+		gdb_tx_ok();
+		break;
+	}
+	case 'q':	/* General query. */
+		if (gdb_rx_equal("fThreadInfo")) {
+			thr_iter = kgdb_thr_first();
+			gdb_tx_begin('m');
+			gdb_tx_hex(thr_iter->td_tid, 8);
+			gdb_tx_end();
+		} else if (gdb_rx_equal("sThreadInfo")) {
+			if (thr_iter == NULL) {
+				gdb_tx_err(ENXIO);
+				break;
+			}
+			thr_iter = kgdb_thr_next(thr_iter);
+			if (thr_iter != NULL) {
+				gdb_tx_begin('m');
+				gdb_tx_hex(thr_iter->td_tid, 8);
+				gdb_tx_end();
+			} else {
+				gdb_tx_begin('l');
+				gdb_tx_end();
+			}
+		} else if (!gdb_cpu_query())
+			gdb_tx_empty();
+		break;
+	case 'T': {     /* Thread alive. */
+		intmax_t tid;
+		gdb_rx_varhex(&tid);
+		if (kgdb_thr_lookup(tid) != NULL)
+			gdb_tx_ok();
+		else
+			gdb_tx_err(ENOENT);
+		break;
+	}
+	case -1:
+		/* Empty command. Treat as unknown command. */
+		/* FALLTHROUGH */
+	default:
+		/* Unknown command. Send empty response. */
+		gdb_tx_empty();
+		break;
+	}
+}
+
 /*
  * Functions to receive and extract from a packet.
  */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200406110558.i5B5waNX027918>