From owner-freebsd-dtrace@FreeBSD.ORG Sun Sep 15 22:16:29 2013 Return-Path: Delivered-To: freebsd-dtrace@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTP id CAD6C629 for ; Sun, 15 Sep 2013 22:16:29 +0000 (UTC) (envelope-from markjdb@gmail.com) Received: from mail-yh0-x235.google.com (mail-yh0-x235.google.com [IPv6:2607:f8b0:4002:c01::235]) (using TLSv1 with cipher ECDHE-RSA-RC4-SHA (128/128 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 8F67228E4 for ; Sun, 15 Sep 2013 22:16:29 +0000 (UTC) Received: by mail-yh0-f53.google.com with SMTP id b20so1668813yha.26 for ; Sun, 15 Sep 2013 15:16:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:date:from:to:cc:subject:message-id:mime-version:content-type :content-disposition:user-agent; bh=EjiLOwkUSJQ8YzhRYW1jg14jzsAZfNlBHCy5/1pCdNo=; b=lK3v7HnYTRYMghF6W0+uNQklwEm1h3EGg4jyETbnljX7WH9D+SON//bx3o3etU576w LMWbRZ9EPrkckuwwvOVYS1/xVW8QSKM/zY0yc0B6z4cKrTvLU8vrv/c5GUMVgbJg7PcA bJXN0/7Hy1M6LxWSrq76d0T4YmqpktFD8Xpn3Dy5yT06IzdQnTiY5og7AQDcPuq4Q+lD y/yhR0IIFidZ6uegeqIYjZsRUMe8MRt/Wnqz3U3YYRBmBx+vWhQrtIc5oAIjPQ8+82YL ruBpgFBhhJ8JCIeGAsjVY45MZd0KvOVDRVYGYU6p7HXUX2bXMyNhzj8DDdDs+RkVXlO6 ix0A== X-Received: by 10.236.83.69 with SMTP id p45mr24664126yhe.40.1379283388647; Sun, 15 Sep 2013 15:16:28 -0700 (PDT) Received: from raichu (24-212-218-13.cable.teksavvy.com. [24.212.218.13]) by mx.google.com with ESMTPSA id t62sm638340yhd.26.1969.12.31.16.00.00 (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Sun, 15 Sep 2013 15:16:28 -0700 (PDT) Sender: Mark Johnston Date: Sun, 15 Sep 2013 18:16:23 -0400 From: Mark Johnston To: dtrace-discuss@lists.dtrace.org Subject: pr_psargs on FreeBSD Message-ID: <20130915221622.GA2981@raichu> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.5.21 (2010-09-15) Cc: freebsd-dtrace@freebsd.org X-BeenThere: freebsd-dtrace@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "A discussion list for developers working on DTrace in FreeBSD." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 15 Sep 2013 22:16:29 -0000 Hi! One of the problems with FreeBSD's DTrace implementation is that it doesn't have a good way of getting the arguments of a given process. This is because of the way that they're stored, which is as a single buffer with null-terminator between consecutive arguments. In particular, there is no way within DTrace to convert such a buffer to a single string (say by replacing all but the last terminator with spaces). So scripts like execsnoop will only print the first element of a process' argv on FreeBSD, which isn't particularly helpful for interpreted programs. You can get a fixed number of arguments with something like printf("%s %s %s", cupsinfo->pr_psargs, curpsinfo->pr_psargs + strlen(curpsinfo->pr_psargs) + 1, curpsinfo->pr_psargs + strlen(curpsinfo->pr_psargs) + 1 + strlen(curpsinfo->pr_psargs + strlen(curpsinfo->pr_psargs) + 1) + 1); but this is less than ideal. :) Apparently OS X has the same problem, but I don't have a machine to test with, so I'm not completely sure. It seems to me that there are two ways to solve this problem: change the format that FreeBSD uses to store process arguments, or add a function to DTrace which can convert the argument buffer to a string. I'm not too keen on the former approach, so here's a proposal for the latter. It'd be great to get some feedback on it and find out whether anyone thinks it's a terrible idea. :) It's kind of a strong-armed approach, but the problem's been around for a while and I can't think of any clever solutions - I'd love to see an alternative solution. My patch against FreeBSD (pasted below) adds a function called memstr() to DTrace. memstr() takes three arguments: addr, c, and len, and returns a copy of addr of length len with all null-terminators replaced by c, and with the last byte replaced by a null-terminator. In particular, memstr() always returns a string of length len - 1, unless len == 0, in which case we return the empty string. With this function, the translator for the pr_psargs fields becomes translator psinfo_t < struct proc *T > { ... pr_psargs = memstr(T->p_args->ar_args, ' ', T->p_args->ar_length); ... }; and execsnoop works properly. Any thoughts on this function? Have I missed a better solution? A patch for FreeBSD is below. Thanks, -Mark diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c index 9c9b2a6..83c81e5 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c @@ -122,8 +122,9 @@ #define DT_VERS_1_8_1 DT_VERSION_NUMBER(1, 8, 1) #define DT_VERS_1_9 DT_VERSION_NUMBER(1, 9, 0) #define DT_VERS_1_9_1 DT_VERSION_NUMBER(1, 9, 1) -#define DT_VERS_LATEST DT_VERS_1_9_1 -#define DT_VERS_STRING "Sun D 1.9.1" +#define DT_VERS_1_9_2 DT_VERSION_NUMBER(1, 9, 2) +#define DT_VERS_LATEST DT_VERS_1_9_2 +#define DT_VERS_STRING "Sun D 1.9.2" const dt_version_t _dtrace_versions[] = { DT_VERS_1_0, /* D API 1.0.0 (PSARC 2001/466) Solaris 10 FCS */ @@ -145,6 +146,7 @@ const dt_version_t _dtrace_versions[] = { DT_VERS_1_8_1, /* D API 1.8.1 */ DT_VERS_1_9, /* D API 1.9 */ DT_VERS_1_9_1, /* D API 1.9.1 */ + DT_VERS_1_9_2, /* D API 1.9.2 */ 0 }; @@ -311,6 +313,8 @@ static const dt_ident_t _dtrace_globals[] = { &dt_idops_func, "void(@)" }, { "memref", DT_IDENT_FUNC, 0, DIF_SUBR_MEMREF, DT_ATTR_STABCMN, DT_VERS_1_1, &dt_idops_func, "uintptr_t *(void *, size_t)" }, +{ "memstr", DT_IDENT_FUNC, 0, DIF_SUBR_MEMSTR, DT_ATTR_STABCMN, DT_VERS_1_0, + &dt_idops_func, "string(void *, char, size_t)" }, { "min", DT_IDENT_AGGFUNC, 0, DTRACEAGG_MIN, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(@)" }, { "mod", DT_IDENT_ACTFUNC, 0, DT_ACT_MOD, DT_ATTR_STABCMN, diff --git a/cddl/lib/libdtrace/psinfo.d b/cddl/lib/libdtrace/psinfo.d index 068e72e..b2a009a 100644 --- a/cddl/lib/libdtrace/psinfo.d +++ b/cddl/lib/libdtrace/psinfo.d @@ -57,7 +57,7 @@ translator psinfo_t < struct proc *T > { pr_gid = T->p_ucred->cr_rgid; pr_egid = T->p_ucred->cr_groups[0]; pr_addr = 0; - pr_psargs = stringof(T->p_args->ar_args); + pr_psargs = memstr(T->p_args->ar_args, ' ', T->p_args->ar_length); pr_arglen = T->p_args->ar_length; pr_jailid = T->p_ucred->cr_prison->pr_id; }; diff --git a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c index babc42c4..6d991fb 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c +++ b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c @@ -4920,6 +4920,38 @@ inetout: regs[rd] = (uintptr_t)end + 1; break; } + case DIF_SUBR_MEMSTR: { + char *str = (char *)mstate->dtms_scratch_ptr; + uintptr_t mem = tupregs[0].dttk_value; + char c = tupregs[1].dttk_value; + size_t size = tupregs[2].dttk_value; + uint8_t n; + int i; + + regs[rd] = 0; + + if (size == 0) + break; + + if (!dtrace_canload(mem, size - 1, mstate, vstate)) + break; + + if (!DTRACE_INSCRATCH(mstate, size)) { + DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); + break; + } + + for (i = 0; i < size - 1; i++) { + n = dtrace_load8(mem++); + str[i] = (n == 0) ? c : n; + } + str[size - 1] = 0; + + regs[rd] = (uintptr_t)str; + mstate->dtms_scratch_ptr += size; + break; + } + case DIF_SUBR_TYPEREF: { uintptr_t size = 4 * sizeof(uintptr_t); uintptr_t *typeref = (uintptr_t *) P2ROUNDUP(mstate->dtms_scratch_ptr, sizeof(uintptr_t)); @@ -9102,6 +9134,7 @@ dtrace_difo_validate_helper(dtrace_difo_t *dp) subr == DIF_SUBR_NTOHL || subr == DIF_SUBR_NTOHLL || subr == DIF_SUBR_MEMREF || + subr == DIF_SUBR_MEMSTR || subr == DIF_SUBR_TYPEREF) break; diff --git a/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h b/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h index 8728e30..295457c 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h +++ b/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h @@ -311,8 +311,9 @@ typedef enum dtrace_probespec { #define DIF_SUBR_SX_SHARED_HELD 48 #define DIF_SUBR_SX_EXCLUSIVE_HELD 49 #define DIF_SUBR_SX_ISEXCLUSIVE 50 +#define DIF_SUBR_MEMSTR 51 -#define DIF_SUBR_MAX 50 /* max subroutine value */ +#define DIF_SUBR_MAX 51 /* max subroutine value */ typedef uint32_t dif_instr_t;