/* * getoffsets - read the magic offsets from the specified file */ static void getoffsets( off_t *tick_off, off_t *tickadj_off, off_t *dosync_off, off_t *noprintf_off ) { #ifndef NOKMEM # ifndef HAVE_KVM_OPEN const char **kname; # endif #endif #ifndef NOKMEM # ifdef NLIST_NAME_UNION # define NL_B {{ # define NL_E }} # else # define NL_B { # define NL_E } # endif #endif #define K_FILLER_NAME "DavidLetterman" #ifdef NLIST_EXTRA_INDIRECTION int i; #endif #ifndef NOKMEM static struct nlist nl[] = { NL_B #ifdef K_TICKADJ_NAME #define N_TICKADJ 0 K_TICKADJ_NAME #else K_FILLER_NAME #endif NL_E, NL_B #ifdef K_TICK_NAME #define N_TICK 1 K_TICK_NAME #else K_FILLER_NAME #endif NL_E, NL_B #ifdef K_DOSYNCTODR_NAME #define N_DOSYNC 2 K_DOSYNCTODR_NAME #else K_FILLER_NAME #endif NL_E, NL_B #ifdef K_NOPRINTF_NAME #define N_NOPRINTF 3 K_NOPRINTF_NAME #else K_FILLER_NAME #endif NL_E, NL_B "" NL_E, }; #ifndef HAVE_KVM_OPEN static const char *kernels[] = { #ifdef HAVE_GETBOOTFILE NULL, /* *** SEE BELOW! *** */ #endif "/kernel/unix", "/kernel", "/vmunix", "/unix", "/mach", "/hp-ux", "/386bsd", "/netbsd", "/stand/vmunix", "/bsd", NULL }; #endif /* not HAVE_KVM_OPEN */ #ifdef HAVE_KVM_OPEN /* * Solaris > 2.5 doesn't have a kernel file. Use the kvm_* interface * to read the kernel name list. -- stolcke 3/4/96 */ kvm_t *kvm_handle = kvm_open(NULL, NULL, NULL, O_RDONLY, progname); if (kvm_handle == NULL) { (void) fprintf(stderr, "%s: kvm_open failed\n", progname); exit(1); } if (kvm_nlist(kvm_handle, nl) == -1) { (void) fprintf(stderr, "%s: kvm_nlist failed\n", progname); exit(1); } kvm_close(kvm_handle); #else /* not HAVE_KVM_OPEN */ #ifdef HAVE_GETBOOTFILE /* *** SEE HERE! *** */ if (kernels[0] == NULL) { char * cp = (char *)getbootfile(); if (cp) { kernels[0] = cp; } else { kernels[0] = "/Placeholder"; } } #endif /* HAVE_GETBOOTFILE */ for (kname = kernels; *kname != NULL; kname++) { struct stat stbuf; if (stat(*kname, &stbuf) == -1) { continue; } if (nlist(*kname, nl) >= 0) { break; } else { (void) fprintf(stderr, "%s: nlist didn't find needed symbols from <%s>: %s\n", progname, *kname, strerror(errno)); } } if (*kname == NULL) { (void) fprintf(stderr, "%s: Couldn't find the kernel\n", progname); exit(1); } #endif /* HAVE_KVM_OPEN */ if (dokmem) { file = kmem; fd = openfile(file, O_RDONLY); #ifdef NLIST_EXTRA_INDIRECTION /* * Go one more round of indirection. */ for (i = 0; i < (sizeof(nl) / sizeof(struct nlist)); i++) { if ((nl[i].n_value) && (nl[i].n_sclass == 0x6b)) { readvar(fd, nl[i].n_value, &nl[i].n_value); } } #endif /* NLIST_EXTRA_INDIRECTION */ } #endif /* not NOKMEM */ *tickadj_off = 0; *tick_off = 0; *dosync_off = 0; *noprintf_off = 0; #if defined(N_TICKADJ) *tickadj_off = nl[N_TICKADJ].n_value; #endif #if defined(N_TICK) *tick_off = nl[N_TICK].n_value; #endif #if defined(N_DOSYNC) *dosync_off = nl[N_DOSYNC].n_value; #endif #if defined(N_NOPRINTF) *noprintf_off = nl[N_NOPRINTF].n_value; #endif return; }
static kvm_t * _kvm_open(kvm_t *kd, const char *uf, const char *mf, int flag, char *errout) { struct stat st; kd->vmfd = -1; kd->pmfd = -1; kd->nlfd = -1; kd->vmst = 0; kd->procbase = 0; kd->argspc = 0; kd->argv = 0; if (uf == 0) uf = getbootfile(); else if (strlen(uf) >= MAXPATHLEN) { _kvm_err(kd, kd->program, "exec file name too long"); goto failed; } if (flag & ~O_RDWR) { _kvm_err(kd, kd->program, "bad flags arg"); goto failed; } if (mf == 0) mf = _PATH_MEM; if ((kd->pmfd = open(mf, flag | O_CLOEXEC, 0)) < 0) { _kvm_syserr(kd, kd->program, "%s", mf); goto failed; } if (fstat(kd->pmfd, &st) < 0) { _kvm_syserr(kd, kd->program, "%s", mf); goto failed; } if (S_ISREG(st.st_mode) && st.st_size <= 0) { errno = EINVAL; _kvm_syserr(kd, kd->program, "empty file"); goto failed; } if (S_ISCHR(st.st_mode)) { /* * If this is a character special device, then check that * it's /dev/mem. If so, open kmem too. (Maybe we should * make it work for either /dev/mem or /dev/kmem -- in either * case you're working with a live kernel.) */ if (strcmp(mf, _PATH_DEVNULL) == 0) { kd->vmfd = open(_PATH_DEVNULL, O_RDONLY | O_CLOEXEC); return (kd); } else if (strcmp(mf, _PATH_MEM) == 0) { if ((kd->vmfd = open(_PATH_KMEM, flag | O_CLOEXEC)) < 0) { _kvm_syserr(kd, kd->program, "%s", _PATH_KMEM); goto failed; } return (kd); } } /* * This is a crash dump. * Initialize the virtual address translation machinery, * but first setup the namelist fd. */ if ((kd->nlfd = open(uf, O_RDONLY | O_CLOEXEC, 0)) < 0) { _kvm_syserr(kd, kd->program, "%s", uf); goto failed; } if (strncmp(mf, _PATH_FWMEM, strlen(_PATH_FWMEM)) == 0) kd->rawdump = 1; if (_kvm_initvtop(kd) < 0) goto failed; return (kd); failed: /* * Copy out the error if doing sane error semantics. */ if (errout != 0) strlcpy(errout, kd->errbuf, _POSIX2_LINE_MAX); (void)kvm_close(kd); return (0); }
static void DoFile(const char *savedir, const char *device) { static char *buf = NULL; struct partinfo dpart; struct kerneldumpheader kdhf, kdhl; off_t mediasize, dumpsize, firsthd, lasthd, dmpcnt; FILE *info, *fp, *fpkern; mode_t oumask; int fd, fdinfo, fdkernin, error, wl; int nr, nw, hs, he = 0; int bounds, status; u_int sectorsize; bounds = getbounds(); dmpcnt = 0; mediasize = 0; status = STATUS_UNKNOWN; if (buf == NULL) { buf = malloc(BUFFERSIZE); if (buf == NULL) { syslog(LOG_ERR, "%m"); return; } } if (verbose) printf("checking for kernel dump on device %s\n", device); fd = open(device, O_RDWR); if (fd < 0) { syslog(LOG_ERR, "%s: %m", device); return; } bzero(&dpart, sizeof(dpart)); error = ioctl(fd, DIOCGPART, &dpart); if (error) { syslog(LOG_ERR, "couldn't find media and/or sector size of %s: %m", device); goto closefd; } mediasize = dpart.media_size; sectorsize = dpart.media_blksize; if (verbose) { printf("mediasize = %lld\n", (long long)mediasize); printf("sectorsize = %u\n", sectorsize); } lasthd = mediasize - sectorsize; lseek(fd, lasthd, SEEK_SET); error = read(fd, &kdhl, sizeof kdhl); if (error != sizeof kdhl) { syslog(LOG_ERR, "error reading last dump header at offset %lld in %s: %m", (long long)lasthd, device); goto closefd; } if (memcmp(kdhl.magic, KERNELDUMPMAGIC, sizeof kdhl.magic)) { if (verbose) printf("magic mismatch on last dump header on %s\n", device); status = STATUS_BAD; if (force == 0) goto closefd; if (memcmp(kdhl.magic, KERNELDUMPMAGIC_CLEARED, sizeof kdhl.magic) == 0) { if (verbose) printf("forcing magic on %s\n", device); memcpy(kdhl.magic, KERNELDUMPMAGIC, sizeof kdhl.magic); } else { syslog(LOG_ERR, "unable to force dump - bad magic"); goto closefd; } } if (dtoh32(kdhl.version) != KERNELDUMPVERSION) { syslog(LOG_ERR, "unknown version (%d) in last dump header on %s", dtoh32(kdhl.version), device); status = STATUS_BAD; if (force == 0) goto closefd; } nfound++; if (clear) goto nuke; if (kerneldump_parity(&kdhl)) { syslog(LOG_ERR, "parity error on last dump header on %s", device); nerr++; status = STATUS_BAD; if (force == 0) goto closefd; } dumpsize = dtoh64(kdhl.dumplength); firsthd = lasthd - dumpsize - sizeof kdhf; lseek(fd, firsthd, SEEK_SET); error = read(fd, &kdhf, sizeof kdhf); if (error != sizeof kdhf) { syslog(LOG_ERR, "error reading first dump header at offset %lld in %s: %m", (long long)firsthd, device); nerr++; goto closefd; } if (verbose >= 2) { printf("First dump headers:\n"); printheader(stdout, &kdhf, device, bounds, -1); printf("\nLast dump headers:\n"); printheader(stdout, &kdhl, device, bounds, -1); printf("\n"); } if (memcmp(&kdhl, &kdhf, sizeof kdhl)) { syslog(LOG_ERR, "first and last dump headers disagree on %s", device); nerr++; status = STATUS_BAD; if (force == 0) goto closefd; } else { status = STATUS_GOOD; } if (checkfor) { printf("A dump exists on %s\n", device); close(fd); exit(0); } if (kdhl.panicstring[0]) syslog(LOG_ALERT, "reboot after panic: %s", kdhl.panicstring); else syslog(LOG_ALERT, "reboot"); if (verbose) printf("Checking for available free space\n"); if (!check_space(savedir, dumpsize)) { nerr++; goto closefd; } writebounds(bounds + 1); /* * Write kernel file. */ fdkernin = open(getbootfile(), O_RDONLY, 0); if (fdkernin < 0) { syslog(LOG_ERR, "%s: %m", getbootfile()); } if (compress) { sprintf(buf, "kern.%d.gz", bounds); fpkern = zopen(buf, "w"); } else { sprintf(buf, "kern.%d", bounds); fpkern = fopen(buf, "w"); } if (fpkern == NULL) { syslog(LOG_ERR, "%s: %m", buf); close(fdkernin); } syslog(LOG_NOTICE, "writing %skernel to %s", compress ? "compressed " : "", buf); while ((nr = read(fdkernin, buf, sizeof(buf))) > 0) { nw = fwrite(buf, 1, nr, fpkern); if (nw != nr) { syslog(LOG_ERR, "kern.%d: %m", bounds); syslog(LOG_WARNING, "WARNING: kernel may be incomplete"); exit(1); } } if (nr < 0) { syslog(LOG_ERR, "%s: %m", getbootfile()); syslog(LOG_WARNING, "WARNING: kernel may be incomplete"); exit(1); } fclose(fpkern); close(fdkernin); sprintf(buf, "info.%d", bounds); /* * Create or overwrite any existing dump header files. */ fdinfo = open(buf, O_WRONLY | O_CREAT | O_TRUNC, 0600); if (fdinfo < 0) { syslog(LOG_ERR, "%s: %m", buf); nerr++; goto closefd; } oumask = umask(S_IRWXG|S_IRWXO); /* Restrict access to the core file.*/ if (compress) { sprintf(buf, "vmcore.%d.gz", bounds); fp = zopen(buf, "w"); } else { sprintf(buf, "vmcore.%d", bounds); fp = fopen(buf, "w"); } if (fp == NULL) { syslog(LOG_ERR, "%s: %m", buf); close(fdinfo); nerr++; goto closefd; } (void)umask(oumask); info = fdopen(fdinfo, "w"); if (info == NULL) { syslog(LOG_ERR, "fdopen failed: %m"); nerr++; goto closefd; } if (verbose) printheader(stdout, &kdhl, device, bounds, status); printheader(info, &kdhl, device, bounds, status); fclose(info); syslog(LOG_NOTICE, "writing %score to %s", compress ? "compressed " : "", buf); while (dumpsize > 0) { wl = BUFFERSIZE; if (wl > dumpsize) wl = dumpsize; nr = read(fd, buf, wl); if (nr != wl) { if (nr == 0) syslog(LOG_WARNING, "WARNING: EOF on dump device"); else syslog(LOG_ERR, "read error on %s: %m", device); nerr++; goto closeall; } if (compress) { nw = fwrite(buf, 1, wl, fp); } else { for (nw = 0; nw < nr; nw = he) { /* find a contiguous block of zeroes */ for (hs = nw; hs < nr; hs += BLOCKSIZE) { for (he = hs; he < nr && buf[he] == 0; ++he) /* nothing */ ; /* is the hole long enough to matter? */ if (he >= hs + BLOCKSIZE) break; } /* back down to a block boundary */ he &= BLOCKMASK; /* * 1) Don't go beyond the end of the buffer. * 2) If the end of the buffer is less than * BLOCKSIZE bytes away, we're at the end * of the file, so just grab what's left. */ if (hs + BLOCKSIZE > nr) hs = he = nr; /* * At this point, we have a partial ordering: * nw <= hs <= he <= nr * If hs > nw, buf[nw..hs] contains non-zero data. * If he > hs, buf[hs..he] is all zeroes. */ if (hs > nw) if (fwrite(buf + nw, hs - nw, 1, fp) != 1) break; if (he > hs) if (fseeko(fp, he - hs, SEEK_CUR) == -1) break; } } if (nw != wl) { syslog(LOG_ERR, "write error on vmcore.%d file: %m", bounds); syslog(LOG_WARNING, "WARNING: vmcore may be incomplete"); nerr++; goto closeall; } if (verbose) { dmpcnt += wl; printf("%llu\r", (unsigned long long)dmpcnt); fflush(stdout); } dumpsize -= wl; } if (verbose) printf("\n"); if (fclose(fp) < 0) { syslog(LOG_ERR, "error on vmcore.%d: %m", bounds); nerr++; goto closeall; } nsaved++; if (verbose) printf("dump saved\n"); nuke: if (clear || !keep) { if (verbose) printf("clearing dump header\n"); memcpy(kdhl.magic, KERNELDUMPMAGIC_CLEARED, sizeof kdhl.magic); lseek(fd, lasthd, SEEK_SET); error = write(fd, &kdhl, sizeof kdhl); if (error != sizeof kdhl) syslog(LOG_ERR, "error while clearing the dump header: %m"); } close(fd); return; closeall: fclose(fp); closefd: close(fd); }
int main(int argc, char **argv) { int ch, mode, disp, accessmode; struct kvmvars kvmvars; const char *systemname; char *kmemf; if (seteuid(getuid()) != 0) { err(1, "seteuid failed\n"); } kmemf = NULL; systemname = NULL; while ((ch = getopt(argc, argv, "M:N:Bbhpr")) != -1) { switch((char)ch) { case 'M': kmemf = optarg; kflag = 1; break; case 'N': systemname = optarg; break; case 'B': Bflag = 1; break; case 'b': bflag = 1; break; case 'h': hflag = 1; break; case 'p': pflag = 1; break; case 'r': rflag = 1; break; default: usage(); } } argc -= optind; argv += optind; #define BACKWARD_COMPATIBILITY #ifdef BACKWARD_COMPATIBILITY if (*argv) { systemname = *argv; if (*++argv) { kmemf = *argv; ++kflag; } } #endif if (systemname == NULL) systemname = getbootfile(); accessmode = openfiles(systemname, kmemf, &kvmvars); mode = getprof(&kvmvars); if (hflag) disp = GMON_PROF_OFF; else if (Bflag) disp = GMON_PROF_HIRES; else if (bflag) disp = GMON_PROF_ON; else disp = mode; if (pflag) dumpstate(&kvmvars); if (rflag) reset(&kvmvars); if (accessmode == O_RDWR) setprof(&kvmvars, disp); (void)fprintf(stdout, "kgmon: kernel profiling is %s.\n", disp == GMON_PROF_OFF ? "off" : disp == GMON_PROF_HIRES ? "running (high resolution)" : disp == GMON_PROF_ON ? "running" : disp == GMON_PROF_BUSY ? "busy" : disp == GMON_PROF_ERROR ? "off (error)" : "in an unknown state"); return (0); }
int main(int argc, char **argv) { int ch, i, jflag, npcbs; const char *core, *syst; nl[0].n_name = strdup("_tcp_debug"); nl[1].n_name = strdup("_tcp_debx"); jflag = npcbs = 0; while ((ch = getopt(argc, argv, "afjp:st")) != -1) switch (ch) { case 'a': ++aflag; break; case 'f': ++follow; setlinebuf(stdout); break; case 'j': ++jflag; break; case 'p': if (npcbs >= TCP_NDEBUG) errx(1, "too many pcb's specified"); (void)sscanf(optarg, "%x", (int *)&tcp_pcbs[npcbs++]); break; case 's': ++sflag; break; case 't': ++tflag; break; case '?': default: usage(); } argc -= optind; argv += optind; core = _PATH_KMEM; if (argc > 0) { syst = *argv; argc--, argv++; if (argc > 0) { core = *argv; argc--, argv++; ++kflag; } /* * Discard setgid privileges if not the running kernel so that * bad guys can't print interesting stuff from kernel memory. */ if (setgid(getgid()) != 0) err(1, "setgid"); } else syst = getbootfile(); if (nlist(syst, nl) < 0 || !nl[0].n_value) errx(1, "%s: no namelist", syst); if ((memf = open(core, O_RDONLY)) < 0) err(2, "%s", core); if (setgid(getgid()) != 0) err(1, "setgid"); if (kflag) errx(1, "can't do core files yet"); (void)klseek(memf, (off_t)nl[N_TCP_DEBX].n_value, L_SET); if (read(memf, (char *)&tcp_debx, sizeof(tcp_debx)) != sizeof(tcp_debx)) err(3, "tcp_debx"); (void)klseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET); if (read(memf, (char *)tcp_debug, sizeof(tcp_debug)) != sizeof(tcp_debug)) err(3, "tcp_debug"); /* * If no control blocks have been specified, figure * out how many distinct one we have and summarize * them in tcp_pcbs for sorting the trace records * below. */ if (!npcbs) { for (i = 0; i < TCP_NDEBUG; i++) { register struct tcp_debug *td = &tcp_debug[i]; register int j; if (td->td_tcb == 0) continue; for (j = 0; j < npcbs; j++) if (tcp_pcbs[j] == td->td_tcb) break; if (j >= npcbs) tcp_pcbs[npcbs++] = td->td_tcb; } if (!npcbs) exit(0); } qsort(tcp_pcbs, npcbs, sizeof(caddr_t), numeric); if (jflag) { for (i = 0;;) { printf("%p", (void *)tcp_pcbs[i]); if (++i == npcbs) break; fputs(", ", stdout); } putchar('\n'); } else for (i = 0; i < npcbs; i++) { printf("\n%p:\n", tcp_pcbs[i]); dotrace(tcp_pcbs[i]); } exit(0); }
int main(int argc, char *argv[]) { char path[PATH_MAX]; struct stat st; struct captured_main_args args; char *s; int a, ch; dumpnr = NULL; strlcpy(crashdir, "/var/crash", sizeof(crashdir)); s = getenv("KGDB_CRASH_DIR"); if (s != NULL) strlcpy(crashdir, s, sizeof(crashdir)); /* Convert long options into short options. */ for (a = 1; a < argc; a++) { s = argv[a]; if (s[0] == '-') { s++; /* Long options take either 1 or 2 dashes. */ if (s[0] == '-') s++; if (strcmp(s, "quiet") == 0) argv[a] = "-q"; else if (strcmp(s, "fullname") == 0) argv[a] = "-f"; } } kgdb_quiet = 0; memset (&args, 0, sizeof args); args.interpreter_p = INTERP_CONSOLE; args.argv = malloc(sizeof(char *)); args.argv[0] = argv[0]; while ((ch = getopt(argc, argv, "ab:c:d:fn:qr:vw")) != -1) { switch (ch) { case 'a': annotation_level++; break; case 'b': { int i; char *p; i = strtol(optarg, &p, 0); if (*p != '\0' || p == optarg) warnx("warning: could not set baud rate to `%s'.\n", optarg); else baud_rate = i; break; } 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 'f': annotation_level = 1; break; case 'n': /* use dump with given number. */ dumpnr = optarg; break; case 'q': kgdb_quiet = 1; add_arg(&args, "-q"); break; 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 'w': /* core file is writeable. */ add_arg(&args, "--write"); break; case '?': default: usage(); } } if (((vmcore != NULL) ? 1 : 0) + ((dumpnr != NULL) ? 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 (argc > optind) kernel = strdup(argv[optind++]); if (argc > optind && (dumpnr != NULL || remote != NULL)) { warnx("options -n and -r do not take a core file. Ignored"); optind = argc; } if (dumpnr != NULL) { snprintf(path, sizeof(path), "%s/vmcore.%s", crashdir, dumpnr); if (stat(path, &st) == -1) err(1, "%s", path); if (!S_ISREG(st.st_mode)) errx(1, "%s: not a regular file", path); vmcore = strdup(path); } else if (remote != NULL) { verify_remote(); } 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) { if (vmcore != NULL) warnx("core file: %s", vmcore); if (remote != NULL) warnx("device file: %s", remote); if (kernel != NULL) warnx("kernel image: %s", kernel); } /* A remote target requires an explicit kernel argument. */ if (remote != NULL && kernel == NULL) { warnx("remote debugging requires a kernel"); usage(); /* NOTREACHED */ } /* If we don't have a kernel image yet, try to find one. */ if (kernel == NULL) { if (dumpnr != NULL) kernel_from_dumpnr(dumpnr); if (kernel == NULL) errx(1, "couldn't find a suitable kernel image"); if (verbose) warnx("kernel image: %s", kernel); } /* Set an alternate prompt. */ add_arg(&args, "-iex"); add_arg(&args, "set prompt (kgdb) "); /* Open the vmcore if requested. */ if (vmcore != NULL) { add_arg(&args, "-ex"); if (asprintf(&s, "target vmcore %s", vmcore) < 0) err(1, "couldn't build command line"); add_arg(&args, s); } /* Open the remote target if requested. */ if (remote != NULL) { add_arg(&args, "-ex"); if (asprintf(&s, "target remote %s", remote) < 0) err(1, "couldn't build command line"); add_arg(&args, s); } add_arg(&args, kernel); /* The libgdb code uses optind too. Reset it... */ optind = 0; /* Terminate argv list. */ add_arg(&args, NULL); return (gdb_main(&args)); }