ddb_capture.c revision 178515
1178515Srwatson/*- 2178515Srwatson * Copyright (c) 2008 Robert N. M. Watson 3178515Srwatson * All rights reserved. 4178515Srwatson * 5178515Srwatson * Redistribution and use in source and binary forms, with or without 6178515Srwatson * modification, are permitted provided that the following conditions 7178515Srwatson * are met: 8178515Srwatson * 1. Redistributions of source code must retain the above copyright 9178515Srwatson * notice, this list of conditions and the following disclaimer. 10178515Srwatson * 2. Redistributions in binary form must reproduce the above copyright 11178515Srwatson * notice, this list of conditions and the following disclaimer in the 12178515Srwatson * documentation and/or other materials provided with the distribution. 13178515Srwatson * 14178515Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15178515Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16178515Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17178515Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18178515Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19178515Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20178515Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21178515Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22178515Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23178515Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24178515Srwatson * SUCH DAMAGE. 25178515Srwatson */ 26178515Srwatson 27178515Srwatson#include <sys/cdefs.h> 28178515Srwatson__FBSDID("$FreeBSD: head/sbin/ddb/ddb_capture.c 178515 2008-04-25 17:34:09Z rwatson $"); 29178515Srwatson 30178515Srwatson#include <sys/types.h> 31178515Srwatson#include <sys/sysctl.h> 32178515Srwatson 33178515Srwatson#include <err.h> 34178515Srwatson#include <errno.h> 35178515Srwatson#include <fcntl.h> 36178515Srwatson#include <kvm.h> 37178515Srwatson#include <limits.h> 38178515Srwatson#include <stdio.h> 39178515Srwatson#include <stdlib.h> 40178515Srwatson#include <string.h> 41178515Srwatson#include <sysexits.h> 42178515Srwatson#include <unistd.h> 43178515Srwatson 44178515Srwatson#include "ddb.h" 45178515Srwatson 46178515Srwatson/* 47178515Srwatson * Interface with the ddb(4) capture buffer of a live kernel using sysctl, or 48178515Srwatson * for a crash dump using libkvm. 49178515Srwatson */ 50178515Srwatson#define SYSCTL_DDB_CAPTURE_BUFOFF "debug.ddb.capture.bufoff" 51178515Srwatson#define SYSCTL_DDB_CAPTURE_BUFSIZE "debug.ddb.capture.bufsize" 52178515Srwatson#define SYSCTL_DDB_CAPTURE_MAXBUFSIZE "debug.ddb.capture.maxbufsize" 53178515Srwatson#define SYSCTL_DDB_CAPTURE_DATA "debug.ddb.capture.data" 54178515Srwatson#define SYSCTL_DDB_CAPTURE_INPROGRESS "debug.ddb.capture.inprogress" 55178515Srwatson 56178515Srwatsonstatic struct nlist namelist[] = { 57178515Srwatson#define X_DB_CAPTURE_BUF 0 58178515Srwatson { .n_name = "_db_capture_buf" }, 59178515Srwatson#define X_DB_CAPTURE_BUFSIZE 1 60178515Srwatson { .n_name = "_db_capture_bufsize" }, 61178515Srwatson#define X_DB_CAPTURE_MAXBUFSIZE 2 62178515Srwatson { .n_name = "_db_capture_maxbufsize" }, 63178515Srwatson#define X_DB_CAPTURE_BUFOFF 3 64178515Srwatson { .n_name = "_db_capture_bufoff" }, 65178515Srwatson#define X_DB_CAPTURE_INPROGRESS 4 66178515Srwatson { .n_name = "_db_capture_inprogress" }, 67178515Srwatson { .n_name = "" }, 68178515Srwatson}; 69178515Srwatson 70178515Srwatsonstatic int 71178515Srwatsonkread(kvm_t *kvm, void *kvm_pointer, void *address, size_t size, 72178515Srwatson size_t offset) 73178515Srwatson{ 74178515Srwatson ssize_t ret; 75178515Srwatson 76178515Srwatson ret = kvm_read(kvm, (unsigned long)kvm_pointer + offset, address, 77178515Srwatson size); 78178515Srwatson if (ret < 0 || (size_t)ret != size) 79178515Srwatson return (-1); 80178515Srwatson return (0); 81178515Srwatson} 82178515Srwatson 83178515Srwatsonstatic int 84178515Srwatsonkread_symbol(kvm_t *kvm, int index, void *address, size_t size, 85178515Srwatson size_t offset) 86178515Srwatson{ 87178515Srwatson ssize_t ret; 88178515Srwatson 89178515Srwatson ret = kvm_read(kvm, namelist[index].n_value + offset, address, size); 90178515Srwatson if (ret < 0 || (size_t)ret != size) 91178515Srwatson return (-1); 92178515Srwatson return (0); 93178515Srwatson} 94178515Srwatson 95178515Srwatsonstatic void 96178515Srwatsonddb_capture_print_kvm(kvm_t *kvm) 97178515Srwatson{ 98178515Srwatson u_int db_capture_bufsize; 99178515Srwatson char *buffer, *db_capture_buf; 100178515Srwatson 101178515Srwatson if (kread_symbol(kvm, X_DB_CAPTURE_BUF, &db_capture_buf, 102178515Srwatson sizeof(db_capture_buf), 0) < 0) 103178515Srwatson errx(-1, "kvm: unable to read db_capture_buf"); 104178515Srwatson 105178515Srwatson if (kread_symbol(kvm, X_DB_CAPTURE_BUFSIZE, &db_capture_bufsize, 106178515Srwatson sizeof(db_capture_bufsize), 0) < 0) 107178515Srwatson errx(-1, "kvm: unable to read db_capture_bufsize"); 108178515Srwatson 109178515Srwatson buffer = malloc(db_capture_bufsize + 1); 110178515Srwatson if (buffer == NULL) 111178515Srwatson err(-1, "malloc: db_capture_bufsize (%u)", 112178515Srwatson db_capture_bufsize); 113178515Srwatson bzero(buffer, db_capture_bufsize + 1); 114178515Srwatson 115178515Srwatson if (kread(kvm, db_capture_buf, buffer, db_capture_bufsize, 0) < 0) 116178515Srwatson errx(-1, "kvm: unable to read buffer"); 117178515Srwatson 118178515Srwatson printf("%s\n", buffer); 119178515Srwatson free(buffer); 120178515Srwatson} 121178515Srwatson 122178515Srwatsonstatic void 123178515Srwatsonddb_capture_print_sysctl(void) 124178515Srwatson{ 125178515Srwatson size_t buflen, len; 126178515Srwatson char *buffer; 127178515Srwatson int ret; 128178515Srwatson 129178515Srwatsonrepeat: 130178515Srwatson if (sysctlbyname(SYSCTL_DDB_CAPTURE_DATA, NULL, &buflen, NULL, 0) < 0) 131178515Srwatson err(EX_OSERR, "sysctl: %s", SYSCTL_DDB_CAPTURE_DATA); 132178515Srwatson if (buflen == 0) 133178515Srwatson return; 134178515Srwatson buffer = malloc(buflen); 135178515Srwatson if (buffer == NULL) 136178515Srwatson err(EX_OSERR, "malloc"); 137178515Srwatson bzero(buffer, buflen); 138178515Srwatson len = buflen; 139178515Srwatson ret = sysctlbyname(SYSCTL_DDB_CAPTURE_DATA, buffer, &len, NULL, 0); 140178515Srwatson if (ret < 0 && errno != ENOMEM) 141178515Srwatson err(EX_OSERR, "sysctl: %s", SYSCTL_DDB_CAPTURE_DATA); 142178515Srwatson if (ret < 0) { 143178515Srwatson free(buffer); 144178515Srwatson goto repeat; 145178515Srwatson } 146178515Srwatson 147178515Srwatson printf("%s\n", buffer); 148178515Srwatson free(buffer); 149178515Srwatson} 150178515Srwatson 151178515Srwatsonstatic void 152178515Srwatsonddb_capture_status_kvm(kvm_t *kvm) 153178515Srwatson{ 154178515Srwatson u_int db_capture_bufoff, db_capture_bufsize, db_capture_inprogress; 155178515Srwatson 156178515Srwatson if (kread_symbol(kvm, X_DB_CAPTURE_BUFOFF, &db_capture_bufoff, 157178515Srwatson sizeof(db_capture_bufoff), 0) < 0) 158178515Srwatson errx(-1, "kvm: unable to read db_capture_bufoff"); 159178515Srwatson if (kread_symbol(kvm, X_DB_CAPTURE_BUFSIZE, &db_capture_bufsize, 160178515Srwatson sizeof(db_capture_bufsize), 0) < 0) 161178515Srwatson errx(-1, "kvm: unable to read db_capture_bufsize"); 162178515Srwatson if (kread_symbol(kvm, X_DB_CAPTURE_INPROGRESS, 163178515Srwatson &db_capture_inprogress, sizeof(db_capture_inprogress), 0) < 0) 164178515Srwatson err(-1, "kvm: unable to read db_capture_inpgoress"); 165178515Srwatson printf("%u/%u bytes used\n", db_capture_bufoff, db_capture_bufsize); 166178515Srwatson if (db_capture_inprogress) 167178515Srwatson printf("capture is on\n"); 168178515Srwatson else 169178515Srwatson printf("capture is off\n"); 170178515Srwatson 171178515Srwatson} 172178515Srwatson 173178515Srwatsonstatic void 174178515Srwatsonddb_capture_status_sysctl(void) 175178515Srwatson{ 176178515Srwatson u_int db_capture_bufoff, db_capture_bufsize, db_capture_inprogress; 177178515Srwatson size_t len; 178178515Srwatson 179178515Srwatson len = sizeof(db_capture_bufoff); 180178515Srwatson if (sysctlbyname(SYSCTL_DDB_CAPTURE_BUFOFF, &db_capture_bufoff, &len, 181178515Srwatson NULL, 0) < 0) 182178515Srwatson err(EX_OSERR, "sysctl: %s", SYSCTL_DDB_CAPTURE_BUFOFF); 183178515Srwatson len = sizeof(db_capture_bufoff); 184178515Srwatson if (sysctlbyname(SYSCTL_DDB_CAPTURE_BUFSIZE, &db_capture_bufsize, 185178515Srwatson &len, NULL, 0) < 0) 186178515Srwatson err(EX_OSERR, "sysctl: %s", SYSCTL_DDB_CAPTURE_BUFSIZE); 187178515Srwatson len = sizeof(db_capture_inprogress); 188178515Srwatson if (sysctlbyname(SYSCTL_DDB_CAPTURE_INPROGRESS, 189178515Srwatson &db_capture_inprogress, &len, NULL, 0) < 0) 190178515Srwatson err(EX_OSERR, "sysctl: %s", SYSCTL_DDB_CAPTURE_INPROGRESS); 191178515Srwatson printf("%u/%u bytes used\n", db_capture_bufoff, db_capture_bufsize); 192178515Srwatson if (db_capture_inprogress) 193178515Srwatson printf("capture is on\n"); 194178515Srwatson else 195178515Srwatson printf("capture is off\n"); 196178515Srwatson} 197178515Srwatson 198178515Srwatsonvoid 199178515Srwatsonddb_capture(int argc, char *argv[]) 200178515Srwatson{ 201178515Srwatson char *mflag, *nflag, errbuf[_POSIX2_LINE_MAX]; 202178515Srwatson kvm_t *kvm; 203178515Srwatson int ch; 204178515Srwatson 205178515Srwatson mflag = NULL; 206178515Srwatson nflag = NULL; 207178515Srwatson while ((ch = getopt(argc, argv, "M:N:")) != -1) { 208178515Srwatson switch (ch) { 209178515Srwatson case 'M': 210178515Srwatson mflag = optarg; 211178515Srwatson break; 212178515Srwatson 213178515Srwatson case 'N': 214178515Srwatson nflag = optarg; 215178515Srwatson break; 216178515Srwatson 217178515Srwatson default: 218178515Srwatson usage(); 219178515Srwatson } 220178515Srwatson } 221178515Srwatson argc -= optind; 222178515Srwatson argv += optind; 223178515Srwatson 224178515Srwatson if (argc != 1) 225178515Srwatson usage(); 226178515Srwatson 227178515Srwatson if (mflag != NULL) { 228178515Srwatson kvm = kvm_openfiles(nflag, mflag, NULL, O_RDONLY, errbuf); 229178515Srwatson if (kvm == NULL) 230178515Srwatson errx(-1, "ddb_capture: kvm_openfiles: %s", errbuf); 231178515Srwatson if (kvm_nlist(kvm, namelist) != 0) 232178515Srwatson errx(-1, "ddb_capture: kvm_nlist"); 233178515Srwatson } else if (nflag != NULL) 234178515Srwatson usage(); 235178515Srwatson if (strcmp(argv[0], "print") == 0) { 236178515Srwatson if (kvm != NULL) 237178515Srwatson ddb_capture_print_kvm(kvm); 238178515Srwatson else 239178515Srwatson ddb_capture_print_sysctl(); 240178515Srwatson } else if (strcmp(argv[0], "status") == 0) { 241178515Srwatson if (kvm != NULL) 242178515Srwatson ddb_capture_status_kvm(kvm); 243178515Srwatson else 244178515Srwatson ddb_capture_status_sysctl(); 245178515Srwatson } else 246178515Srwatson usage(); 247178515Srwatson} 248