From patchwork Thu May 12 07:43:19 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Marchevsky X-Patchwork-Id: 12847264 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id F2E3BC433FE for ; Thu, 12 May 2022 07:43:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1351141AbiELHno (ORCPT ); Thu, 12 May 2022 03:43:44 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38248 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1351137AbiELHnl (ORCPT ); Thu, 12 May 2022 03:43:41 -0400 Received: from mx0b-00082601.pphosted.com (mx0b-00082601.pphosted.com [67.231.153.30]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D4E261A15E7 for ; Thu, 12 May 2022 00:43:40 -0700 (PDT) Received: from pps.filterd (m0109331.ppops.net [127.0.0.1]) by mx0a-00082601.pphosted.com (8.17.1.5/8.17.1.5) with ESMTP id 24BMwgpq003879 for ; Thu, 12 May 2022 00:43:40 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fb.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : content-type; s=facebook; bh=GAWHF80PzUf5Vy5JJlMs/tfXeR0+CBf77VMkcjKXBXI=; b=J5drIK5CX5+arikxBGDc/pdK7aSbIZivXnRml40SeSJQqMBoY0NXRGNms1CQvxPginOz spnp3wWbtDqF6kmB1KMUxtp1fQK+FBXfOAXzJTo7A1bc23Jie5N90fSNGAvNYX08KyKs B5RybbvPAnSEQrFG/MXSEUMsqzQKwm0M4TY= Received: from maileast.thefacebook.com ([163.114.130.16]) by mx0a-00082601.pphosted.com (PPS) with ESMTPS id 3g04pmrt6d-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT) for ; Thu, 12 May 2022 00:43:39 -0700 Received: from twshared8508.05.ash9.facebook.com (2620:10d:c0a8:1b::d) by mail.thefacebook.com (2620:10d:c0a8:82::c) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.24; Thu, 12 May 2022 00:43:39 -0700 Received: by devbig077.ldc1.facebook.com (Postfix, from userid 158236) id 3497D78F7CCC; Thu, 12 May 2022 00:43:29 -0700 (PDT) From: Dave Marchevsky To: CC: Alexei Starovoitov , Andrii Nakryiko , Daniel Borkmann , Rik van Riel , Ilya Leoshkevich , Yonghong Song , , Dave Marchevsky Subject: [RFC PATCH bpf-next 3/5] libbpf: usdt lib wiring of xmm reads Date: Thu, 12 May 2022 00:43:19 -0700 Message-ID: <20220512074321.2090073-4-davemarchevsky@fb.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220512074321.2090073-1-davemarchevsky@fb.com> References: <20220512074321.2090073-1-davemarchevsky@fb.com> MIME-Version: 1.0 X-FB-Internal: Safe X-Proofpoint-ORIG-GUID: A9hHejmrZESVU9Fw_9DsHBNVWrGkedLZ X-Proofpoint-GUID: A9hHejmrZESVU9Fw_9DsHBNVWrGkedLZ X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.858,Hydra:6.0.486,FMLib:17.11.64.514 definitions=2022-05-11_07,2022-05-12_01,2022-02-23_01 Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net X-Patchwork-State: RFC Handle xmm0,...,xmm15 registers when parsing USDT arguments. Currently only the first 64 bits of the fetched value are returned as I haven't seen the rest of the register used in practice. This patch also handles floats in USDT arg spec by ignoring the fact that they're floats and considering them scalar. Currently we can't do float math in BPF programs anyways, so might as well support passing to userspace and converting there. We can use existing ARG_REG sscanf + logic, adding XMM-specific logic when calc_pt_regs_off fails. If the reg is xmm, arg_spec's reg_off is repurposed to hold reg_no, which is passed to bpf_get_reg_val. Since the helper does the digging around in fxregs_state it's not necessary to calculate offset in bpf code for these regs. NOTE: Changes here cause verification failure for existing USDT tests. Specifically, BPF_USDT prog 'usdt12' fails to verify due to too many insns despite not having its insn count significantly changed. Signed-off-by: Dave Marchevsky --- tools/lib/bpf/usdt.bpf.h | 36 ++++++++++++++++++++-------- tools/lib/bpf/usdt.c | 51 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 73 insertions(+), 14 deletions(-) diff --git a/tools/lib/bpf/usdt.bpf.h b/tools/lib/bpf/usdt.bpf.h index 4181fddb3687..7b5ed4cbaa2f 100644 --- a/tools/lib/bpf/usdt.bpf.h +++ b/tools/lib/bpf/usdt.bpf.h @@ -43,6 +43,7 @@ enum __bpf_usdt_arg_type { BPF_USDT_ARG_CONST, BPF_USDT_ARG_REG, BPF_USDT_ARG_REG_DEREF, + BPF_USDT_ARG_XMM_REG, }; struct __bpf_usdt_arg_spec { @@ -129,7 +130,9 @@ int bpf_usdt_arg(struct pt_regs *ctx, __u64 arg_num, long *res) { struct __bpf_usdt_spec *spec; struct __bpf_usdt_arg_spec *arg_spec; - unsigned long val; + struct pt_regs *btf_regs; + struct task_struct *btf_task; + struct { __u64 a; __u64 unused; } val = {}; int err, spec_id; *res = 0; @@ -151,7 +154,7 @@ int bpf_usdt_arg(struct pt_regs *ctx, __u64 arg_num, long *res) /* Arg is just a constant ("-4@$-9" in USDT arg spec). * value is recorded in arg_spec->val_off directly. */ - val = arg_spec->val_off; + val.a = arg_spec->val_off; break; case BPF_USDT_ARG_REG: /* Arg is in a register (e.g, "8@%rax" in USDT arg spec), @@ -159,7 +162,20 @@ int bpf_usdt_arg(struct pt_regs *ctx, __u64 arg_num, long *res) * struct pt_regs. To keep things simple user-space parts * record offsetof(struct pt_regs, ) in arg_spec->reg_off. */ - err = bpf_probe_read_kernel(&val, sizeof(val), (void *)ctx + arg_spec->reg_off); + err = bpf_probe_read_kernel(&val.a, sizeof(val.a), (void *)ctx + arg_spec->reg_off); + if (err) + return err; + break; + case BPF_USDT_ARG_XMM_REG: + /* Same as above, but arg is an xmm reg, so can't look + * in pt_regs, need to use special helper. + * reg_off is the regno ("xmm0" -> regno 0, etc) + */ + btf_task = bpf_get_current_task_btf(); + btf_regs = (struct pt_regs *)bpf_task_pt_regs(btf_task); + err = bpf_get_reg_val(&val, sizeof(val), + ((u64)arg_spec->reg_off + BPF_GETREG_X86_XMM0) << 32, + btf_regs, btf_task); if (err) return err; break; @@ -171,14 +187,14 @@ int bpf_usdt_arg(struct pt_regs *ctx, __u64 arg_num, long *res) * from pt_regs, then do another user-space probe read to * fetch argument value itself. */ - err = bpf_probe_read_kernel(&val, sizeof(val), (void *)ctx + arg_spec->reg_off); + err = bpf_probe_read_kernel(&val.a, sizeof(val.a), (void *)ctx + arg_spec->reg_off); if (err) return err; - err = bpf_probe_read_user(&val, sizeof(val), (void *)val + arg_spec->val_off); + err = bpf_probe_read_user(&val.a, sizeof(val.a), (void *)val.a + arg_spec->val_off); if (err) return err; #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - val >>= arg_spec->arg_bitshift; + val.a >>= arg_spec->arg_bitshift; #endif break; default: @@ -189,12 +205,12 @@ int bpf_usdt_arg(struct pt_regs *ctx, __u64 arg_num, long *res) * necessary upper arg_bitshift bits, with sign extension if argument * is signed */ - val <<= arg_spec->arg_bitshift; + val.a <<= arg_spec->arg_bitshift; if (arg_spec->arg_signed) - val = ((long)val) >> arg_spec->arg_bitshift; + val.a = ((long)val.a) >> arg_spec->arg_bitshift; else - val = val >> arg_spec->arg_bitshift; - *res = val; + val.a = val.a >> arg_spec->arg_bitshift; + *res = val.a; return 0; } diff --git a/tools/lib/bpf/usdt.c b/tools/lib/bpf/usdt.c index f1c9339cfbbc..3cac48959ff9 100644 --- a/tools/lib/bpf/usdt.c +++ b/tools/lib/bpf/usdt.c @@ -199,6 +199,7 @@ enum usdt_arg_type { USDT_ARG_CONST, USDT_ARG_REG, USDT_ARG_REG_DEREF, + USDT_ARG_XMM_REG, }; /* should match exactly struct __bpf_usdt_arg_spec from usdt.bpf.h */ @@ -1218,7 +1219,41 @@ static int calc_pt_regs_off(const char *reg_name) } } - pr_warn("usdt: unrecognized register '%s'\n", reg_name); + return -ENOENT; +} + +static int calc_xmm_regno(const char *reg_name) +{ + static struct { + const char *name; + __u16 regno; + } xmm_reg_map[] = { + { "xmm0", 0 }, + { "xmm1", 1 }, + { "xmm2", 2 }, + { "xmm3", 3 }, + { "xmm4", 4 }, + { "xmm5", 5 }, + { "xmm6", 6 }, + { "xmm7", 7 }, +#ifdef __x86_64__ + { "xmm8", 8 }, + { "xmm9", 9 }, + { "xmm10", 10 }, + { "xmm11", 11 }, + { "xmm12", 12 }, + { "xmm13", 13 }, + { "xmm14", 14 }, + { "xmm15", 15 }, +#endif + }; + int i; + + for (i = 0; i < ARRAY_SIZE(xmm_reg_map); i++) { + if (strcmp(reg_name, xmm_reg_map[i].name) == 0) + return xmm_reg_map[i].regno; + } + return -ENOENT; } @@ -1234,18 +1269,26 @@ static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec arg->val_off = off; reg_off = calc_pt_regs_off(reg_name); free(reg_name); - if (reg_off < 0) + if (reg_off < 0) { + pr_warn("usdt: unrecognized register '%s'\n", reg_name); return reg_off; + } arg->reg_off = reg_off; - } else if (sscanf(arg_str, " %d @ %%%ms %n", &arg_sz, ®_name, &len) == 2) { + } else if (sscanf(arg_str, " %d %*[f@] %%%ms %n", &arg_sz, ®_name, &len) == 2) { /* Register read case, e.g., -4@%eax */ arg->arg_type = USDT_ARG_REG; arg->val_off = 0; reg_off = calc_pt_regs_off(reg_name); + if (reg_off < 0) { + reg_off = calc_xmm_regno(reg_name); + arg->arg_type = USDT_ARG_XMM_REG; + } free(reg_name); - if (reg_off < 0) + if (reg_off < 0) { + pr_warn("usdt: unrecognized register '%s'\n", reg_name); return reg_off; + } arg->reg_off = reg_off; } else if (sscanf(arg_str, " %d @ $%ld %n", &arg_sz, &off, &len) == 2) { /* Constant value case, e.g., 4@$71 */