// SPDX-License-Identifier: GPL-2.0-or-later
/*
* probe-file.c : operate ftrace k/uprobe events files
*
* Written by Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
*/
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <linux/zalloc.h>
#include "namespaces.h"
#include "event.h"
#include "strlist.h"
#include "strfilter.h"
#include "debug.h"
#include "build-id.h"
#include "dso.h"
#include "color.h"
#include "symbol.h"
#include "strbuf.h"
#include <api/fs/tracing_path.h>
#include <api/fs/fs.h>
#include "probe-event.h"
#include "probe-file.h"
#include "session.h"
#include "perf_regs.h"
#include "string2.h"
/* 4096 - 2 ('\n' + '\0') */
#define MAX_CMDLEN 4094
static bool print_common_warning(int err, bool readwrite)
{
if (err == -EACCES)
pr_warning("No permission to %s tracefs.\nPlease %s\n",
readwrite ? "write" : "read",
readwrite ? "run this command again with sudo." :
"try 'sudo mount -o remount,mode=755 /sys/kernel/tracing/'");
else
return false;
return true;
}
static bool print_configure_probe_event(int kerr, int uerr)
{
const char *config, *file;
if (kerr == -ENOENT && uerr == -ENOENT) {
file = "{k,u}probe_events";
config = "CONFIG_KPROBE_EVENTS=y and CONFIG_UPROBE_EVENTS=y";
} else if (kerr == -ENOENT) {
file = "kprobe_events";
config = "CONFIG_KPROBE_EVENTS=y";
} else if (uerr == -ENOENT) {
file = "uprobe_events";
config = "CONFIG_UPROBE_EVENTS=y";
} else
return false;
if (!debugfs__configured() && !tracefs__configured())
pr_warning("Debugfs or tracefs is not mounted\n"
"Please try 'sudo mount -t tracefs nodev /sys/kernel/tracing/'\n");
else
pr_warning("%s/%s does not exist.\nPlease rebuild kernel with %s.\n",
tracing_path_mount(), file, config);
return true;
}
static void print_open_warning(int err, bool uprobe, bool readwrite)
{
char sbuf[STRERR_BUFSIZE];
if (print_common_warning(err, readwrite))
return;
if (print_configure_probe_event(uprobe ? 0 : err, uprobe ? err : 0))
return;
pr_warning("Failed to open %s/%cprobe_events: %s\n",
tracing_path_mount(), uprobe ? 'u' : 'k',
str_error_r(-err, sbuf, sizeof(sbuf)));
}
static void print_both_open_warning(int kerr, int uerr, bool readwrite)
{
char sbuf[STRERR_BUFSIZE];
if (kerr == uerr && print_common_warning(kerr, readwrite))
return;
if (print_configure_probe_event(kerr, uerr))
return;
if (kerr < 0)
pr_warning("Failed to open %s/kprobe_events: %s.\n",
tracing_path_mount(),
str_error_r(-kerr, sbuf, sizeof(sbuf)));
if (uerr < 0)
pr_warning("Failed to open %s/uprobe_events: %s.\n",
tracing_path_mount(),
str_error_r(-uerr, sbuf, sizeof(sbuf)));
}
int open_trace_file(const char *trace_file, bool readwrite)
{
char buf[PATH_MAX];
int ret;
ret = e_snprintf(buf, PATH_MAX, "%s/%s", tracing_path_mount(), trace_file);
if (ret >= 0) {
pr_debug("Opening %s write=%d\n", buf, readwrite);
if (readwrite && !probe_event_dry_run)
ret = open(buf, O_RDWR | O_APPEND, 0);
else
ret = open(buf, O_RDONLY, 0);
if (ret < 0)
ret = -errno;
}
return ret;
}
static int open_kprobe_events(bool readwrite)
{
return open_trace_file("kprobe_events", readw