mirror of
https://github.com/freebsd/freebsd-src.git
synced 2024-12-04 12:28:58 +00:00
Implement a "kill" DDB command which is an interface to psignal() that
respects locks. Before SMPng, one was able to call psignal() using the "call" command, but this is no longer possible because it does not respect locks by itself. This is very useful when one has gotten their machine into a state where it is impossible to spawn ps/kill or su to root. In this case, respecting locks essentially means trying to aquire the proc lock before calling psignal(). We can't block in the debugger, so if trylock fails, the operation fails. This also means that we can't use pfind(), since that will attempt to lock the process for us. Reviewed by: jhb
This commit is contained in:
parent
629c25d4a9
commit
19d2c78f34
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=86998
@ -36,7 +36,11 @@
|
||||
*/
|
||||
#include <sys/param.h>
|
||||
#include <sys/linker_set.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/reboot.h>
|
||||
#include <sys/signalvar.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/cons.h>
|
||||
|
||||
@ -63,6 +67,7 @@ SET_DECLARE(db_show_cmd_set, struct command);
|
||||
|
||||
static db_cmdfcn_t db_fncall;
|
||||
static db_cmdfcn_t db_gdb;
|
||||
static db_cmdfcn_t db_kill;
|
||||
static db_cmdfcn_t db_reset;
|
||||
|
||||
/* XXX this is actually forward-static. */
|
||||
@ -418,6 +423,7 @@ static struct command db_command_table[] = {
|
||||
{ "ps", db_ps, 0, 0 },
|
||||
{ "gdb", db_gdb, 0, 0 },
|
||||
{ "reset", db_reset, 0, 0 },
|
||||
{ "kill", db_kill, CS_OWN, 0 },
|
||||
{ (char *)0, }
|
||||
};
|
||||
|
||||
@ -573,6 +579,59 @@ db_gdb (dummy1, dummy2, dummy3, dummy4)
|
||||
: "DDB debugger");
|
||||
}
|
||||
|
||||
static void
|
||||
db_kill(dummy1, dummy2, dummy3, dummy4)
|
||||
db_expr_t dummy1;
|
||||
boolean_t dummy2;
|
||||
db_expr_t dummy3;
|
||||
char * dummy4;
|
||||
{
|
||||
db_expr_t old_radix, pid, sig;
|
||||
struct proc *p;
|
||||
|
||||
#define DB_ERROR(f) do { db_printf f; db_flush_lex(); goto out; } while (0)
|
||||
|
||||
/*
|
||||
* PIDs and signal numbers are typically represented in base
|
||||
* 10, so make that the default here. It can, of course, be
|
||||
* overridden by specifying a prefix.
|
||||
*/
|
||||
old_radix = db_radix;
|
||||
db_radix = 10;
|
||||
/* Retrieve arguments. */
|
||||
if (!db_expression(&sig))
|
||||
DB_ERROR(("Missing signal number\n"));
|
||||
if (!db_expression(&pid))
|
||||
DB_ERROR(("Missing process ID\n"));
|
||||
db_skip_to_eol();
|
||||
if (sig < 0 || sig > _SIG_MAXSIG)
|
||||
DB_ERROR(("Signal number out of range\n"));
|
||||
|
||||
/*
|
||||
* Find the process in question. allproc_lock is not needed
|
||||
* since we're in DDB.
|
||||
*/
|
||||
/* sx_slock(&allproc_lock); */
|
||||
LIST_FOREACH(p, &allproc, p_list)
|
||||
if (p->p_pid == pid)
|
||||
break;
|
||||
/* sx_sunlock(&allproc_lock); */
|
||||
if (p == NULL)
|
||||
DB_ERROR(("Can't find process with pid %d\n", pid));
|
||||
|
||||
/* If it's already locked, bail; otherwise, do the deed. */
|
||||
if (PROC_TRYLOCK(p) == 0)
|
||||
DB_ERROR(("Can't lock process with pid %d\n", pid));
|
||||
else {
|
||||
psignal(p, sig);
|
||||
PROC_UNLOCK(p);
|
||||
}
|
||||
|
||||
out:
|
||||
db_radix = old_radix;
|
||||
#undef DB_ERROR
|
||||
}
|
||||
|
||||
static void
|
||||
db_reset(dummy1, dummy2, dummy3, dummy4)
|
||||
db_expr_t dummy1;
|
||||
|
Loading…
Reference in New Issue
Block a user