MFp4 @178364:

Implement an optional delay to the ddb reset/reboot command.

This allows textdumps to be run automatically with unattended reboots
after a resonable timeout, while still permitting an administrator to
break into debugger if attached to the console at the time of the
event for further debugging.  Cap the maximum delay at 1 week to avoid
highly accidental results, and default to 15s in case of problems
parsing the timeout value.

Move hex2dec helper function from db_thread.c to db_command.c to make
it generally available and prefix it with a "db_" to avoid namespace
collisions.

Reviewed by:	rwatson
MFC after:	4 weeks
This commit is contained in:
Bjoern A. Zeeb 2010-05-24 16:41:05 +00:00
parent 3abaa08643
commit 0f59fbc3d6
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=208509
4 changed files with 74 additions and 37 deletions

View File

@ -60,7 +60,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd November 29, 2008
.Dd May 24, 2010
.Dt DDB 4
.Os
.Sh NAME
@ -1092,9 +1092,13 @@ for a list of signals.
Note that the arguments are reversed relative to
.Xr kill 2 .
.Pp
.It Ic reboot
.It Ic reset
.It Ic reboot Op Ar seconds
.It Ic reset Op Ar seconds
Hard reset the system.
If the optional argument
.Ar seconds
is given, the debugger will wait for this long, at most a week,
before rebooting.
.Pp
.It Ic help
Print a short summary of the available commands and command

View File

@ -661,13 +661,42 @@ db_kill(dummy1, dummy2, dummy3, dummy4)
#undef DB_ERROR
}
/*
* Reboot. In case there is an additional argument, take it as delay in
* seconds. Default to 15s if we cannot parse it and make sure we will
* never wait longer than 1 week. Some code is similar to
* kern_shutdown.c:shutdown_panic().
*/
#ifndef DB_RESET_MAXDELAY
#define DB_RESET_MAXDELAY (3600 * 24 * 7)
#endif
static void
db_reset(dummy1, dummy2, dummy3, dummy4)
db_expr_t dummy1;
boolean_t dummy2;
db_expr_t dummy3;
char * dummy4;
db_reset(db_expr_t addr, boolean_t have_addr, db_expr_t count __unused,
char *modif __unused)
{
int delay, loop;
if (have_addr) {
delay = (int)db_hex2dec(addr);
/* If we parse to fail, use 15s. */
if (delay == -1)
delay = 15;
/* Cap at one week. */
if ((uintmax_t)delay > (uintmax_t)DB_RESET_MAXDELAY)
delay = DB_RESET_MAXDELAY;
db_printf("Automatic reboot in %d seconds - "
"press a key on the console to abort\n", delay);
for (loop = delay * 10; loop > 0; --loop) {
DELAY(1000 * 100); /* 1/10th second */
/* Did user type a key? */
if (cncheckc() != -1)
return;
}
}
cpu_reset();
}
@ -771,3 +800,28 @@ db_stack_trace_all(db_expr_t dummy, boolean_t dummy2, db_expr_t dummy3,
kdb_jmpbuf(prev_jb);
}
}
/*
* Take the parsed expression value from the command line that was parsed
* as a hexadecimal value and convert it as if the expression was parsed
* as a decimal value. Returns -1 if the expression was not a valid
* decimal value.
*/
db_expr_t
db_hex2dec(db_expr_t expr)
{
uintptr_t x, y;
db_expr_t val;
y = 1;
val = 0;
x = expr;
while (x != 0) {
if (x % 16 > 9)
return (-1);
val += (x % 16) * (y);
x >>= 4;
y *= 10;
}
return (val);
}

View File

@ -33,6 +33,12 @@
* Author: David B. Golub, Carnegie Mellon University
* Date: 7/90
*/
/*
* Helper functions.
*/
db_expr_t db_hex2dec(db_expr_t expr);
/*
* Command loop declarations.
*/

View File

@ -38,8 +38,6 @@ __FBSDID("$FreeBSD$");
#include <ddb/db_command.h>
#include <ddb/db_sym.h>
static db_expr_t hex2dec(db_expr_t expr);
void
db_print_thread(void)
{
@ -107,31 +105,6 @@ db_show_threads(db_expr_t addr, boolean_t hasaddr, db_expr_t cnt, char *mod)
}
}
/*
* Take the parsed expression value from the command line that was parsed
* as a hexadecimal value and convert it as if the expression was parsed
* as a decimal value. Returns -1 if the expression was not a valid
* decimal value.
*/
static db_expr_t
hex2dec(db_expr_t expr)
{
uintptr_t x, y;
db_expr_t val;
y = 1;
val = 0;
x = expr;
while (x != 0) {
if (x % 16 > 9)
return (-1);
val += (x % 16) * (y);
x >>= 4;
y *= 10;
}
return (val);
}
/*
* Lookup a thread based on a db expression address. We assume that the
* address was parsed in hexadecimal. We reparse the address in decimal
@ -151,7 +124,7 @@ db_lookup_thread(db_expr_t addr, boolean_t check_pid)
* If the parsed address was not a valid decimal expression,
* assume it is a thread pointer.
*/
decaddr = hex2dec(addr);
decaddr = db_hex2dec(addr);
if (decaddr == -1)
return ((struct thread *)addr);
@ -183,7 +156,7 @@ db_lookup_proc(db_expr_t addr)
db_expr_t decaddr;
struct proc *p;
decaddr = hex2dec(addr);
decaddr = db_hex2dec(addr);
if (decaddr != -1) {
FOREACH_PROC_IN_SYSTEM(p) {
if (p->p_pid == decaddr)