From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752552AbbB1Jbm (ORCPT ); Sat, 28 Feb 2015 04:31:42 -0500 Received: from terminus.zytor.com ([198.137.202.10]:44989 "EHLO terminus.zytor.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751210AbbB1Jb0 (ORCPT ); Sat, 28 Feb 2015 04:31:26 -0500 Date: Sat, 28 Feb 2015 01:30:51 -0800 From: tip-bot for Masami Hiramatsu Message-ID: Cc: acme@kernel.org, mingo@kernel.org, linux-kernel@vger.kernel.org, hpa@zytor.com, acme@redhat.com, masami.hiramatsu.pt@hitachi.com, tglx@linutronix.de, peterz@infradead.org, namhyung@kernel.org Reply-To: namhyung@kernel.org, peterz@infradead.org, tglx@linutronix.de, mingo@kernel.org, linux-kernel@vger.kernel.org, acme@kernel.org, acme@redhat.com, masami.hiramatsu.pt@hitachi.com, hpa@zytor.com In-Reply-To: <20150219143113.14434.5387.stgit@localhost.localdomain> References: <20150219143113.14434.5387.stgit@localhost.localdomain> To: linux-tip-commits@vger.kernel.org Subject: [tip:perf/core] perf probe: Check kprobes blacklist when adding new events Git-Commit-ID: 9aaf5a5f479bd68699f2e6f6e5e5f1253377b6da X-Mailer: tip-git-log-daemon Robot-ID: Robot-Unsubscribe: Contact to get blacklisted from these emails MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset=UTF-8 Content-Disposition: inline Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Commit-ID: 9aaf5a5f479bd68699f2e6f6e5e5f1253377b6da Gitweb: http://git.kernel.org/tip/9aaf5a5f479bd68699f2e6f6e5e5f1253377b6da Author: Masami Hiramatsu AuthorDate: Thu, 19 Feb 2015 23:31:13 +0900 Committer: Arnaldo Carvalho de Melo CommitDate: Thu, 26 Feb 2015 11:59:05 -0300 perf probe: Check kprobes blacklist when adding new events Recent linux kernel provides a blacklist of the functions which can not be probed. perf probe can now check this blacklist before setting new events and indicate better error message for users. Without this patch, ---- # perf probe --add vmalloc_fault Added new event: Failed to write event: Invalid argument Error: Failed to add events. ---- With this patch ---- # perf probe --add vmalloc_fault Added new event: Warning: Skipped probing on blacklisted function: vmalloc_fault ---- Reported-by: Arnaldo Carvalho de Melo Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20150219143113.14434.5387.stgit@localhost.localdomain Signed-off-by: Masami Hiramatsu Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-event.c | 109 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 108 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 9dfbed9..662d454 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -1903,6 +1903,95 @@ static struct strlist *get_probe_trace_command_rawlist(int fd) return sl; } +struct kprobe_blacklist_node { + struct list_head list; + unsigned long start; + unsigned long end; + char *symbol; +}; + +static void kprobe_blacklist__delete(struct list_head *blacklist) +{ + struct kprobe_blacklist_node *node; + + while (!list_empty(blacklist)) { + node = list_first_entry(blacklist, + struct kprobe_blacklist_node, list); + list_del(&node->list); + free(node->symbol); + free(node); + } +} + +static int kprobe_blacklist__load(struct list_head *blacklist) +{ + struct kprobe_blacklist_node *node; + const char *__debugfs = debugfs_find_mountpoint(); + char buf[PATH_MAX], *p; + FILE *fp; + int ret; + + if (__debugfs == NULL) + return -ENOTSUP; + + ret = e_snprintf(buf, PATH_MAX, "%s/kprobes/blacklist", __debugfs); + if (ret < 0) + return ret; + + fp = fopen(buf, "r"); + if (!fp) + return -errno; + + ret = 0; + while (fgets(buf, PATH_MAX, fp)) { + node = zalloc(sizeof(*node)); + if (!node) { + ret = -ENOMEM; + break; + } + INIT_LIST_HEAD(&node->list); + list_add_tail(&node->list, blacklist); + if (sscanf(buf, "0x%lx-0x%lx", &node->start, &node->end) != 2) { + ret = -EINVAL; + break; + } + p = strchr(buf, '\t'); + if (p) { + p++; + if (p[strlen(p) - 1] == '\n') + p[strlen(p) - 1] = '\0'; + } else + p = (char *)"unknown"; + node->symbol = strdup(p); + if (!node->symbol) { + ret = -ENOMEM; + break; + } + pr_debug2("Blacklist: 0x%lx-0x%lx, %s\n", + node->start, node->end, node->symbol); + ret++; + } + if (ret < 0) + kprobe_blacklist__delete(blacklist); + fclose(fp); + + return ret; +} + +static struct kprobe_blacklist_node * +kprobe_blacklist__find_by_address(struct list_head *blacklist, + unsigned long address) +{ + struct kprobe_blacklist_node *node; + + list_for_each_entry(node, blacklist, list) { + if (node->start <= address && address <= node->end) + return node; + } + + return NULL; +} + /* Show an event */ static int show_perf_probe_event(struct perf_probe_event *pev, const char *module) @@ -2117,6 +2206,8 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, char buf[64]; const char *event, *group; struct strlist *namelist; + LIST_HEAD(blacklist); + struct kprobe_blacklist_node *node; if (pev->uprobes) fd = open_uprobe_events(true); @@ -2134,11 +2225,25 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, pr_debug("Failed to get current event list.\n"); return -EIO; } + /* Get kprobe blacklist if exists */ + if (!pev->uprobes) { + ret = kprobe_blacklist__load(&blacklist); + if (ret < 0) + pr_debug("No kprobe blacklist support, ignored\n"); + } ret = 0; pr_info("Added new event%s\n", (ntevs > 1) ? "s:" : ":"); for (i = 0; i < ntevs; i++) { tev = &tevs[i]; + /* Ensure that the address is NOT blacklisted */ + node = kprobe_blacklist__find_by_address(&blacklist, + tev->point.address); + if (node) { + pr_warning("Warning: Skipped probing on blacklisted function: %s\n", node->symbol); + continue; + } + if (pev->event) event = pev->event; else @@ -2189,13 +2294,15 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, allow_suffix = true; } - if (ret >= 0) { + /* Note that it is possible to skip all events because of blacklist */ + if (ret >= 0 && tev->event) { /* Show how to use the event. */ pr_info("\nYou can now use it in all perf tools, such as:\n\n"); pr_info("\tperf record -e %s:%s -aR sleep 1\n\n", tev->group, tev->event); } + kprobe_blacklist__delete(&blacklist); strlist__delete(namelist); close(fd); return ret;