From patchwork Wed Oct 14 12:41:15 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wang Nan X-Patchwork-Id: 54945 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-lf0-f70.google.com (mail-lf0-f70.google.com [209.85.215.70]) by patches.linaro.org (Postfix) with ESMTPS id B187C23012 for ; Wed, 14 Oct 2015 12:50:33 +0000 (UTC) Received: by lffy185 with SMTP id y185sf561509lff.2 for ; Wed, 14 Oct 2015 05:50:32 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:delivered-to:from:to:cc:subject:date:message-id :in-reply-to:references:mime-version:content-type:sender:precedence :list-id:x-original-sender:x-original-authentication-results :mailing-list:list-post:list-help:list-archive:list-unsubscribe; bh=qsCjnwuYEuFZOj/yZHTalFcuQOxT8zxkjwNP5/miQS0=; b=m9x9Ypn4C0ql2X8s8/7FiI5NK2XCukenVeKkEQmi0SRJZhnykjCtxKI/mTmgPDVcY/ mYZCOlt4Eib6Yy8BGJCFpVVxIYq67rEVFBigfz9cXTxuBJOX9kEnTBFTGwBSPxTxk/Dt 5mSc/8V7fuyahURdKRfDMZeL1Ii42f1MajyawuOnFcLY7VW70Nb8DAWfjOQsqJcoUjBG EBAcydow1Psv6CqdYCCDVxs33RA7zmDZ4j7rWRq+MIZAwf8uiKUGizjWZ/go/Jiri+9S UysCxDTOjRmAtoBGJuIJqw3lslIbBF5FYLrBWMKKk3QWPR/QYf0VvPOGWYuH9/xesg+H DjTQ== X-Gm-Message-State: ALoCoQniGvRT1kNIPaLSrD+MtqsDnOiPvnDnkUlQ4NtLlT+iqEwrtBkJC3KeAjxAmOjZ3zQU4KHx X-Received: by 10.112.55.69 with SMTP id q5mr735410lbp.24.1444827032640; Wed, 14 Oct 2015 05:50:32 -0700 (PDT) X-BeenThere: patchwork-forward@linaro.org Received: by 10.25.158.146 with SMTP id h140ls36122lfe.108.gmail; Wed, 14 Oct 2015 05:50:32 -0700 (PDT) X-Received: by 10.112.140.197 with SMTP id ri5mr1518355lbb.65.1444827032460; Wed, 14 Oct 2015 05:50:32 -0700 (PDT) Received: from mail-lb0-f172.google.com (mail-lb0-f172.google.com. [209.85.217.172]) by mx.google.com with ESMTPS id c5si5468808lbp.10.2015.10.14.05.50.32 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 14 Oct 2015 05:50:32 -0700 (PDT) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.217.172 as permitted sender) client-ip=209.85.217.172; Received: by lbwr8 with SMTP id r8so45159752lbw.2 for ; Wed, 14 Oct 2015 05:50:32 -0700 (PDT) X-Received: by 10.112.132.7 with SMTP id oq7mr1558984lbb.32.1444827032263; Wed, 14 Oct 2015 05:50:32 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.112.59.35 with SMTP id w3csp2713363lbq; Wed, 14 Oct 2015 05:50:29 -0700 (PDT) X-Received: by 10.68.92.194 with SMTP id co2mr3619340pbb.147.1444827028862; Wed, 14 Oct 2015 05:50:28 -0700 (PDT) Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id ht11si13090602pac.98.2015.10.14.05.50.28; Wed, 14 Oct 2015 05:50:28 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932411AbbJNMu0 (ORCPT + 30 others); Wed, 14 Oct 2015 08:50:26 -0400 Received: from szxga01-in.huawei.com ([58.251.152.64]:50247 "EHLO szxga01-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753549AbbJNMmu (ORCPT ); Wed, 14 Oct 2015 08:42:50 -0400 Received: from 172.24.1.49 (EHLO szxeml425-hub.china.huawei.com) ([172.24.1.49]) by szxrg01-dlp.huawei.com (MOS 4.3.7-GA FastPath queued) with ESMTP id CWT05943; Wed, 14 Oct 2015 20:42:24 +0800 (CST) Received: from linux-4hy3.site (10.107.193.248) by szxeml425-hub.china.huawei.com (10.82.67.180) with Microsoft SMTP Server id 14.3.235.1; Wed, 14 Oct 2015 20:42:11 +0800 From: Wang Nan To: , , CC: , , , , , , , , , , , , Wang Nan , Arnaldo Carvalho de Melo Subject: [PATCH 04/31] perf record, bpf: Create probe points for BPF programs Date: Wed, 14 Oct 2015 12:41:15 +0000 Message-ID: <1444826502-49291-5-git-send-email-wangnan0@huawei.com> X-Mailer: git-send-email 1.8.3.4 In-Reply-To: <1444826502-49291-1-git-send-email-wangnan0@huawei.com> References: <1444826502-49291-1-git-send-email-wangnan0@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.107.193.248] X-CFilter-Loop: Reflected Sender: linux-kernel-owner@vger.kernel.org Precedence: list List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: wangnan0@huawei.com X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.217.172 as permitted sender) smtp.mailfrom=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , This patch introduces bpf__{un,}probe() functions to enable callers to create kprobe points based on section names a BPF program. It parses the section names in the program and creates corresponding 'struct perf_probe_event' structures. The parse_perf_probe_command() function is used to do the main parsing work. The resuling 'struct perf_probe_event' is stored into program private data for further using. By utilizing the new probing API, this patch creates probe points during event parsing. To ensure probe points be removed correctly, register an atexit hook so even perf quit through exit() bpf__clear() is still called, so probing points are cleared. Note that bpf_clear() should be registered before bpf__probe() is called, so failure of bpf__probe() can still trigger bpf__clear() to remove probe points which are already probed. strerror style error reporting scaffold is created by this patch. bpf__strerror_probe() is the first error reporting function in bpf-loader.c. Signed-off-by: Wang Nan Cc: Alexei Starovoitov Cc: Brendan Gregg Cc: Daniel Borkmann Cc: David Ahern Cc: He Kuang Cc: Jiri Olsa Cc: Kaixu Xia Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Zefan Li Cc: pi3orama@163.com Signed-off-by: Arnaldo Carvalho de Melo Link: http://lkml.kernel.org/n/ebpf-6yw9eg0ej3l4jnqhinngkw86@git.kernel.org --- tools/perf/util/bpf-loader.c | 222 ++++++++++++++++++++++++++++++++++++++++- tools/perf/util/bpf-loader.h | 30 ++++++ tools/perf/util/parse-events.c | 17 ++++ 3 files changed, 268 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index ab56073..56f6fe8 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c @@ -10,6 +10,8 @@ #include "perf.h" #include "debug.h" #include "bpf-loader.h" +#include "probe-event.h" +#include "probe-finder.h" // for MAX_PROBES #define DEFINE_PRINT_FN(name, level) \ static int libbpf_##name(const char *fmt, ...) \ @@ -27,6 +29,10 @@ DEFINE_PRINT_FN(warning, 0) DEFINE_PRINT_FN(info, 0) DEFINE_PRINT_FN(debug, 1) +struct bpf_prog_priv { + struct perf_probe_event pev; +}; + struct bpf_object *bpf__prepare_load(const char *filename) { struct bpf_object *obj; @@ -52,6 +58,220 @@ void bpf__clear(void) { struct bpf_object *obj, *tmp; - bpf_object__for_each_safe(obj, tmp) + bpf_object__for_each_safe(obj, tmp) { + bpf__unprobe(obj); bpf_object__close(obj); + } +} + +static void +bpf_prog_priv__clear(struct bpf_program *prog __maybe_unused, + void *_priv) +{ + struct bpf_prog_priv *priv = _priv; + + cleanup_perf_probe_events(&priv->pev, 1); + free(priv); +} + +static int +config_bpf_program(struct bpf_program *prog) +{ + struct perf_probe_event *pev = NULL; + struct bpf_prog_priv *priv = NULL; + const char *config_str; + int err; + + config_str = bpf_program__title(prog, false); + if (!config_str) { + pr_debug("bpf: unable to get title for program\n"); + return -EINVAL; + } + + priv = calloc(sizeof(*priv), 1); + if (!priv) { + pr_debug("bpf: failed to alloc priv\n"); + return -ENOMEM; + } + pev = &priv->pev; + + pr_debug("bpf: config program '%s'\n", config_str); + err = parse_perf_probe_command(config_str, pev); + if (err < 0) { + pr_debug("bpf: '%s' is not a valid config string\n", + config_str); + err = -EINVAL; + goto errout; + } + + if (pev->group && strcmp(pev->group, PERF_BPF_PROBE_GROUP)) { + pr_debug("bpf: '%s': group for event is set and not '%s'.\n", + config_str, PERF_BPF_PROBE_GROUP); + err = -EINVAL; + goto errout; + } else if (!pev->group) + pev->group = strdup(PERF_BPF_PROBE_GROUP); + + if (!pev->group) { + pr_debug("bpf: strdup failed\n"); + err = -ENOMEM; + goto errout; + } + + if (!pev->event) { + pr_debug("bpf: '%s': event name is missing\n", + config_str); + err = -EINVAL; + goto errout; + } + pr_debug("bpf: config '%s' is ok\n", config_str); + + err = bpf_program__set_private(prog, priv, bpf_prog_priv__clear); + if (err) { + pr_debug("Failed to set priv for program '%s'\n", config_str); + goto errout; + } + + return 0; + +errout: + if (pev) + clear_perf_probe_event(pev); + free(priv); + return err; +} + +static int bpf__prepare_probe(void) +{ + static int err = 0; + static bool initialized = false; + + /* + * Make err static, so if init failed the first, bpf__prepare_probe() + * fails each time without calling init_probe_symbol_maps multiple + * times. + */ + if (initialized) + return err; + + initialized = true; + err = init_probe_symbol_maps(false); + if (err < 0) + pr_debug("Failed to init_probe_symbol_maps\n"); + probe_conf.max_probes = MAX_PROBES; + return err; +} + +int bpf__probe(struct bpf_object *obj) +{ + int err = 0; + struct bpf_program *prog; + struct bpf_prog_priv *priv; + struct perf_probe_event *pev; + + err = bpf__prepare_probe(); + if (err) { + pr_debug("bpf__prepare_probe failed\n"); + return err; + } + + bpf_object__for_each_program(prog, obj) { + err = config_bpf_program(prog); + if (err) + goto out; + + err = bpf_program__get_private(prog, (void **)&priv); + if (err || !priv) + goto out; + pev = &priv->pev; + + err = convert_perf_probe_events(pev, 1); + if (err < 0) { + pr_debug("bpf_probe: failed to convert perf probe events"); + goto out; + } + + err = apply_perf_probe_events(pev, 1); + if (err < 0) { + pr_debug("bpf_probe: failed to apply perf probe events"); + goto out; + } + } +out: + return err < 0 ? err : 0; +} + +#define EVENTS_WRITE_BUFSIZE 4096 +int bpf__unprobe(struct bpf_object *obj) +{ + int err, ret = 0; + struct bpf_program *prog; + struct bpf_prog_priv *priv; + + bpf_object__for_each_program(prog, obj) { + int i; + + err = bpf_program__get_private(prog, (void **)&priv); + if (err || !priv) + continue; + + for (i = 0; i < priv->pev.ntevs; i++) { + struct probe_trace_event *tev = &priv->pev.tevs[i]; + char name_buf[EVENTS_WRITE_BUFSIZE]; + struct strfilter *delfilter; + + snprintf(name_buf, EVENTS_WRITE_BUFSIZE, + "%s:%s", tev->group, tev->event); + name_buf[EVENTS_WRITE_BUFSIZE - 1] = '\0'; + + delfilter = strfilter__new(name_buf, NULL); + if (!delfilter) { + pr_debug("Failed to create filter for unprobing\n"); + ret = -ENOMEM; + continue; + } + + err = del_perf_probe_events(delfilter); + strfilter__delete(delfilter); + if (err) { + pr_debug("Failed to delete %s\n", name_buf); + ret = err; + continue; + } + } + } + return ret; +} + +#define bpf__strerror_head(err, buf, size) \ + char sbuf[STRERR_BUFSIZE], *emsg;\ + if (!size)\ + return 0;\ + if (err < 0)\ + err = -err;\ + emsg = strerror_r(err, sbuf, sizeof(sbuf));\ + switch (err) {\ + default:\ + scnprintf(buf, size, "%s", emsg);\ + break; + +#define bpf__strerror_entry(val, fmt...)\ + case val: {\ + scnprintf(buf, size, fmt);\ + break;\ + } + +#define bpf__strerror_end(buf, size)\ + }\ + buf[size - 1] = '\0'; + +int bpf__strerror_probe(struct bpf_object *obj __maybe_unused, + int err, char *buf, size_t size) +{ + bpf__strerror_head(err, buf, size); + bpf__strerror_entry(EEXIST, "Probe point exist. Try use 'perf probe -d \"*\"'"); + bpf__strerror_entry(EPERM, "You need to be root, and /proc/sys/kernel/kptr_restrict should be 0\n"); + bpf__strerror_entry(ENOENT, "You need to check probing points in BPF file\n"); + bpf__strerror_end(buf, size); + return 0; } diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h index f402d7c..b819622 100644 --- a/tools/perf/util/bpf-loader.h +++ b/tools/perf/util/bpf-loader.h @@ -11,11 +11,18 @@ #include "debug.h" struct bpf_object; +#define PERF_BPF_PROBE_GROUP "perf_bpf_probe" #ifdef HAVE_LIBBPF_SUPPORT struct bpf_object *bpf__prepare_load(const char *filename); void bpf__clear(void); + +int bpf__probe(struct bpf_object *obj); +int bpf__unprobe(struct bpf_object *obj); +int bpf__strerror_probe(struct bpf_object *obj, int err, + char *buf, size_t size); + #else static inline struct bpf_object * bpf__prepare_load(const char *filename __maybe_unused) @@ -25,5 +32,28 @@ bpf__prepare_load(const char *filename __maybe_unused) } static inline void bpf__clear(void) { } + +static inline int bpf__probe(struct bpf_object *obj __maybe_unused) { return 0;} +static inline int bpf__unprobe(struct bpf_object *obj __maybe_unused) { return 0;} + +static inline int +__bpf_strerror(char *buf, size_t size) +{ + if (!size) + return 0; + strncpy(buf, + "ERROR: eBPF object loading is disabled during compiling.\n", + size); + buf[size - 1] = '\0'; + return 0; +} + +static inline int +bpf__strerror_probe(struct bpf_object *obj __maybe_unused, + int err __maybe_unused, + char *buf, size_t size) +{ + return __bpf_strerror(buf, size); +} #endif #endif diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index a02abd3..06ff8d6 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -536,6 +536,7 @@ int parse_events_load_bpf_obj(struct parse_events_evlist *data, { int err; char errbuf[BUFSIZ]; + static bool registered_unprobe_atexit = false; if (IS_ERR(obj) || !obj) { snprintf(errbuf, sizeof(errbuf), @@ -545,6 +546,22 @@ int parse_events_load_bpf_obj(struct parse_events_evlist *data, } /* + * Register atexit handler before calling bpf__probe() so + * bpf__probe() don't need to unprobe probe points its already + * created when failure. + */ + if (!registered_unprobe_atexit) { + atexit(bpf__clear); + registered_unprobe_atexit = true; + } + + err = bpf__probe(obj); + if (err) { + bpf__strerror_probe(obj, err, errbuf, sizeof(errbuf)); + goto errout; + } + + /* * Temporary add a dummy event here so we can check whether * basic bpf loader works. Following patches will replace * dummy event by useful evsels.