From owner-p4-projects@FreeBSD.ORG Fri Jun 11 05:58:37 2004 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 2440916A4D1; Fri, 11 Jun 2004 05:58:37 +0000 (GMT) Delivered-To: perforce@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id D62EC16A4CE for ; Fri, 11 Jun 2004 05:58:36 +0000 (GMT) Received: from repoman.freebsd.org (repoman.freebsd.org [216.136.204.115]) by mx1.FreeBSD.org (Postfix) with ESMTP id D02BA43D2F for ; Fri, 11 Jun 2004 05:58:36 +0000 (GMT) (envelope-from marcel@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.12.11/8.12.11) with ESMTP id i5B5wavN027921 for ; Fri, 11 Jun 2004 05:58:36 GMT (envelope-from marcel@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.12.11/8.12.11/Submit) id i5B5waNX027918 for perforce@freebsd.org; Fri, 11 Jun 2004 05:58:36 GMT (envelope-from marcel@freebsd.org) Date: Fri, 11 Jun 2004 05:58:36 GMT Message-Id: <200406110558.i5B5waNX027918@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to marcel@freebsd.org using -f From: Marcel Moolenaar To: Perforce Change Reviews Subject: PERFORCE change 54621 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 11 Jun 2004 05:58:37 -0000 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. and parse /var/crash/info. 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 __FBSDID("$FreeBSD$"); +#include +#include #include #include #include @@ -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 #include #include +#include #include #include #include @@ -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(®) || 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. */