Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 26 Nov 2001 16:34:40 +0000
From:      Dima Dorfman <dima@trit.org>
To:        audit@freebsd.org
Cc:        jhb@freebsd.org
Subject:   DDB 'kill' command
Message-ID:  <20011126163445.24CC43EC8@bazooka.trit.org>

next in thread | raw e-mail | index | archive | help
The attached patch implements a 'kill' command in DDB.  Previously, it
was possible to do `call psignal(xxx,yyy)` and have it DTRT.  (This
was very useful when you accidently got your system so deep in the
hole that spawning kill(1) takes forever and even then possibly
doesn't succeed.)  However, psignal() doesn't respect locking by
itself, so trying that now leads to all kinds of badness.  This patch
basically wraps the psignal() call in a 'kill' command that respects
all necessary locks.

Actually, it isn't very clear exactly which locks it should respect.
The debugger is a special case in this way.  This patch uses the
PROC_TRYLOCK macro; if it fails, the command bails out.  Thus, it
can't use pfind()--the latter automatically does a PROC_LOCK--so it
has to walk the allproc list manually.  It does *not* attempt to get a
shared lock on the allproc list.  There is similar code in db_trace.c,
and it doesn't call sx_slock(), either; I asked jhb about this a while
ago, and all he said was that it is intentional.

Please review.

Thanks.

Index: db_command.c
===================================================================
RCS file: /ref/cvsf/src/sys/ddb/db_command.c,v
retrieving revision 1.40
diff -u -r1.40 db_command.c
--- db_command.c	2001/11/05 21:50:55	1.40
+++ db_command.c	2001/11/26 00:52:40
@@ -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 @@
 
 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 @@
 	{ "ps",		db_ps,			0,	0 },
 	{ "gdb",	db_gdb,			0,	0 },
 	{ "reset",	db_reset,		0,	0 },
+	{ "kill",	db_kill,		CS_OWN,	0 },
 	{ (char *)0, }
 };
 
@@ -571,6 +577,59 @@
 	db_printf("Next trap will enter %s\n",
 		   boothowto & RB_GDB ? "GDB remote protocol mode"
 				      : "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

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-audit" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20011126163445.24CC43EC8>