summaryrefslogtreecommitdiffstats
path: root/sys/ddb
diff options
context:
space:
mode:
authordd <dd@FreeBSD.org>2001-11-27 19:56:28 +0000
committerdd <dd@FreeBSD.org>2001-11-27 19:56:28 +0000
commitda78f952f391aa86cf6f5b9b872501bc7d130c35 (patch)
tree5e0f8766c5361fccec64230a053d2af21500b83b /sys/ddb
parent05ebaf9058f8cc353ae570684d94fcadd1320fb0 (diff)
downloadFreeBSD-src-da78f952f391aa86cf6f5b9b872501bc7d130c35.zip
FreeBSD-src-da78f952f391aa86cf6f5b9b872501bc7d130c35.tar.gz
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
Diffstat (limited to 'sys/ddb')
-rw-r--r--sys/ddb/db_command.c59
1 files changed, 59 insertions, 0 deletions
diff --git a/sys/ddb/db_command.c b/sys/ddb/db_command.c
index 57b722b..dfbdc10 100644
--- a/sys/ddb/db_command.c
+++ b/sys/ddb/db_command.c
@@ -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, }
};
@@ -574,6 +580,59 @@ db_gdb (dummy1, dummy2, dummy3, dummy4)
}
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;
boolean_t dummy2;
OpenPOWER on IntegriCloud