diff options
author | Robert Watson <rwatson@FreeBSD.org> | 2008-03-31 21:57:24 +0000 |
---|---|---|
committer | Robert Watson <rwatson@FreeBSD.org> | 2008-03-31 21:57:24 +0000 |
commit | d164d35c014133e0c25eef9184dbc6a44b270cec (patch) | |
tree | c1266bb4e240e76237db1068acb8802a202fdafb | |
parent | 26efbba75fa773a82cb11628a0a6e384331276f1 (diff) |
Notes
-rw-r--r-- | sys/conf/files | 1 | ||||
-rw-r--r-- | sys/ddb/db_capture.c | 58 | ||||
-rw-r--r-- | sys/ddb/db_command.c | 1 | ||||
-rw-r--r-- | sys/ddb/db_textdump.c | 28 | ||||
-rw-r--r-- | sys/ddb/ddb.h | 23 | ||||
-rw-r--r-- | sys/kern/kern_shutdown.c | 10 |
6 files changed, 102 insertions, 19 deletions
diff --git a/sys/conf/files b/sys/conf/files index b37dc0fe8897..4dbc4539c90c 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -364,6 +364,7 @@ ddb/db_run.c optional ddb ddb/db_script.c optional ddb ddb/db_sym.c optional ddb ddb/db_thread.c optional ddb +ddb/db_textdump.c optional ddb ddb/db_variables.c optional ddb ddb/db_watch.c optional ddb ddb/db_write_cmd.c optional ddb diff --git a/sys/ddb/db_capture.c b/sys/ddb/db_capture.c index 4e6dd7ccdb30..bbc7925fb4c0 100644 --- a/sys/ddb/db_capture.c +++ b/sys/ddb/db_capture.c @@ -57,11 +57,13 @@ static MALLOC_DEFINE(M_DB_CAPTURE, "db_capture", "DDB capture buffer"); #define DB_CAPTURE_DEFAULTBUFSIZE 48*1024 #define DB_CAPTURE_MAXBUFSIZE 512*1024 +#define DB_CAPTURE_FILENAME "ddb.txt" /* Captured DDB output. */ static char *db_capture_buf; static u_int db_capture_bufsize = DB_CAPTURE_DEFAULTBUFSIZE; static u_int db_capture_maxbufsize = DB_CAPTURE_MAXBUFSIZE; /* Read-only. */ static u_int db_capture_bufoff; /* Next location to write in buffer. */ +static u_int db_capture_bufpadding; /* Amount of zero padding. */ static int db_capture_inpager; /* Suspend capture in pager. */ static int db_capture_inprogress; /* DDB capture currently in progress. */ @@ -79,6 +81,14 @@ SYSCTL_UINT(_debug_ddb_capture, OID_AUTO, maxbufsize, CTLFLAG_RD, "Maximum value for debug.ddb.capture.bufsize"); /* + * Various compile-time assertions: defaults must be even multiples of + * textdump block size. We also perform run-time checking of + * user-configurable values. + */ +CTASSERT(DB_CAPTURE_DEFAULTBUFSIZE % TEXTDUMP_BLOCKSIZE == 0); +CTASSERT(DB_CAPTURE_MAXBUFSIZE % TEXTDUMP_BLOCKSIZE == 0); + +/* * Boot-time allocation of the DDB capture buffer, if any. */ static void @@ -86,9 +96,9 @@ db_capture_sysinit(__unused void *dummy) { TUNABLE_INT_FETCH("debug.ddb.capture.bufsize", &db_capture_bufsize); + db_capture_bufsize = roundup(db_capture_bufsize, TEXTDUMP_BLOCKSIZE); if (db_capture_bufsize > DB_CAPTURE_MAXBUFSIZE) db_capture_bufsize = DB_CAPTURE_MAXBUFSIZE; - if (db_capture_bufsize != 0) db_capture_buf = malloc(db_capture_bufsize, M_DB_CAPTURE, M_WAITOK); @@ -110,9 +120,9 @@ sysctl_debug_ddb_capture_bufsize(SYSCTL_HANDLER_ARGS) error = sysctl_handle_int(oidp, &size, 0, req); if (error || req->newptr == NULL) return (error); + size = roundup(size, TEXTDUMP_BLOCKSIZE); if (size > DB_CAPTURE_MAXBUFSIZE) return (EINVAL); - sx_xlock(&db_capture_sx); if (size != 0) { /* @@ -216,6 +226,23 @@ db_capture_exitpager(void) } /* + * Zero out any bytes left in the last block of the DDB capture buffer. This + * is run shortly before writing the blocks to disk, rather than when output + * capture is stopped, in order to avoid injecting nul's into the middle of + * output. + */ +static void +db_capture_zeropad(void) +{ + u_int len; + + len = min(TEXTDUMP_BLOCKSIZE, (db_capture_bufsize - + db_capture_bufoff) % TEXTDUMP_BLOCKSIZE); + bzero(db_capture_buf + db_capture_bufoff, len); + db_capture_bufpadding = len; +} + +/* * Reset capture state, which flushes buffers. */ static void @@ -224,6 +251,7 @@ db_capture_reset(void) db_capture_inprogress = 0; db_capture_bufoff = 0; + db_capture_bufpadding = 0; } /* @@ -242,7 +270,9 @@ db_capture_start(void) } /* - * Terminate DDB output capture. + * Terminate DDB output capture--real work is deferred to db_capture_dump, + * which executes outside of the DDB context. We don't zero pad here because + * capture may be started again before the dump takes place. */ static void db_capture_stop(void) @@ -255,6 +285,28 @@ db_capture_stop(void) db_capture_inprogress = 0; } +/* + * Dump DDB(4) captured output (and resets capture buffers). + */ +void +db_capture_dump(struct dumperinfo *di) +{ + u_int offset; + + if (db_capture_bufoff == 0) + return; + + db_capture_zeropad(); + textdump_mkustar(textdump_block_buffer, DB_CAPTURE_FILENAME, + db_capture_bufoff); + (void)textdump_writenextblock(di, textdump_block_buffer); + for (offset = 0; offset < db_capture_bufoff + db_capture_bufpadding; + offset += TEXTDUMP_BLOCKSIZE) + (void)textdump_writenextblock(di, db_capture_buf + offset); + db_capture_bufoff = 0; + db_capture_bufpadding = 0; +} + /*- * DDB(4) command to manage capture: * diff --git a/sys/ddb/db_command.c b/sys/ddb/db_command.c index b4f8ecc9531c..db6dc24774c5 100644 --- a/sys/ddb/db_command.c +++ b/sys/ddb/db_command.c @@ -146,6 +146,7 @@ static struct command db_commands[] = { { "scripts", db_scripts_cmd, 0, 0 }, { "unscript", db_unscript_cmd, CS_OWN, 0 }, { "capture", db_capture_cmd, CS_OWN, 0 }, + { "textdump", db_textdump_cmd, CS_OWN, 0 }, { (char *)0, } }; diff --git a/sys/ddb/db_textdump.c b/sys/ddb/db_textdump.c index fbfc18f33cb7..237040c60e87 100644 --- a/sys/ddb/db_textdump.c +++ b/sys/ddb/db_textdump.c @@ -25,12 +25,12 @@ */ /*- - * Kernel text-dump support: write a series of text files to the dump - * partition for later recovery, including captured DDB output, kernel - * configuration, message buffer, and panic message. This allows for a more - * compact representation of critical debugging information than traditional - * binary dumps, as well as allowing dump information to be used without - * access to kernel symbols, source code, etc. + * Kernel text-dump support: allow a series of text files to be written to + * the dump partition for later recovery, including captured DDB output, the + * kernel configuration, message buffer, panic message, etc. This allows for + * a more compact representation of critical debugging information than + * traditional binary dumps, as well as allowing dump information to be used + * without access to kernel symbols, source code, etc. * * Storage Layout * -------------- @@ -46,8 +46,9 @@ * know to reverse the order of the blocks in order to produce a readable * file. * - * Data is written out in the ustar file format so that we can write data - * incrementally as a stream without reference to previous files. + * Data is written out in the 'tar' file format, as it provides the facility + * to write data incrementally as a stream without reference to previous + * files. * * TODO * ---- @@ -200,7 +201,7 @@ mkdumpheader(struct kerneldumpheader *kdh, uint32_t archver, } /* - * Calculate and fill in the checksum for a ustar header. + * Calculate and fill in the checksum for a tar header. */ static void ustar_checksum(struct ustar_header *uhp) @@ -259,8 +260,8 @@ textdump_writeblock(struct dumperinfo *di, off_t offset, char *buffer) return (EIO); if (offset < SIZEOF_METADATA) return (ENOSPC); - textdump_error = dump_write(di, buffer, 0, offset + di->mediaoffset, - TEXTDUMP_BLOCKSIZE); + textdump_error = di->dumper(di->priv, buffer, 0, offset + + di->mediaoffset, TEXTDUMP_BLOCKSIZE); return (textdump_error); } @@ -268,9 +269,6 @@ textdump_writeblock(struct dumperinfo *di, off_t offset, char *buffer) * Interfaces to save and restore the dump offset, so that printers can go * back to rewrite a header if required, while avoiding their knowing about * the global layout of the blocks. - * - * If we ever want to support writing textdumps to tape or other - * stream-oriented target, we'll need to remove this. */ void textdump_saveoff(off_t *offsetp) @@ -502,7 +500,7 @@ textdump_dumpsys(struct dumperinfo *di) * Terminate the dump, report any errors, and clear the pending flag. */ if (textdump_error == 0) - (void)dump_write(di, NULL, 0, 0, 0); + (void)di->dumper(di->priv, NULL, 0, 0, 0); if (textdump_error == ENOSPC) printf("Insufficient space on dump partition\n"); else if (textdump_error != 0) diff --git a/sys/ddb/ddb.h b/sys/ddb/ddb.h index ebec60af58a7..d5599785090a 100644 --- a/sys/ddb/ddb.h +++ b/sys/ddb/ddb.h @@ -169,6 +169,7 @@ db_cmdfcn_t db_set_thread; db_cmdfcn_t db_show_regs; db_cmdfcn_t db_show_threads; db_cmdfcn_t db_single_step_cmd; +db_cmdfcn_t db_textdump_cmd; db_cmdfcn_t db_trace_until_call_cmd; db_cmdfcn_t db_trace_until_matching_cmd; db_cmdfcn_t db_unscript_cmd; @@ -212,4 +213,26 @@ void db_capture_writech(char ch); */ void db_script_kdbenter(const char *eventname); /* KDB enter event. */ +/* + * Interface between DDB and the textdump facility. + * + * Text dump blocks are of a fixed size; textdump_block_buffer is a + * statically allocated buffer that code interacting with textdumps can use + * to prepare and hold a pending block in when calling writenextblock(). + */ +#define TEXTDUMP_BLOCKSIZE 512 +extern char textdump_block_buffer[TEXTDUMP_BLOCKSIZE]; + +void textdump_mkustar(char *block_buffer, const char *filename, + u_int size); +void textdump_restoreoff(off_t offset); +void textdump_saveoff(off_t *offsetp); +int textdump_writenextblock(struct dumperinfo *di, char *buffer); + +/* + * Interface between the kernel and textdumps. + */ +extern int textdump_pending; /* Call textdump_dumpsys() instead. */ +void textdump_dumpsys(struct dumperinfo *di); + #endif /* !_DDB_DDB_H_ */ diff --git a/sys/kern/kern_shutdown.c b/sys/kern/kern_shutdown.c index 45f3c7696bba..1262f1b4d39e 100644 --- a/sys/kern/kern_shutdown.c +++ b/sys/kern/kern_shutdown.c @@ -37,6 +37,7 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); +#include "opt_ddb.h" #include "opt_kdb.h" #include "opt_mac.h" #include "opt_panic.h" @@ -64,6 +65,8 @@ __FBSDID("$FreeBSD$"); #include <sys/sysctl.h> #include <sys/sysproto.h> +#include <ddb/ddb.h> + #include <machine/cpu.h> #include <machine/pcb.h> #include <machine/smp.h> @@ -240,7 +243,12 @@ doadump(void) savectx(&dumppcb); dumptid = curthread->td_tid; dumping++; - dumpsys(&dumper); +#ifdef DDB + if (textdump_pending) + textdump_dumpsys(&dumper); + else +#endif + dumpsys(&dumper); } static int |