Commit 4e9e0760 authored by Andrii Nakryiko's avatar Andrii Nakryiko Committed by Alexei Starovoitov

selftests/bpf: make use of PROCMAP_QUERY ioctl if available

Instead of parsing text-based /proc/<pid>/maps file, try to use
PROCMAP_QUERY ioctl() to simplify and speed up data fetching.
This logic is used to do uprobe file offset calculation, so any bugs in
this logic would manifest as failing uprobe BPF selftests.

This also serves as a simple demonstration of one of the intended uses.
Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
Acked-by: default avatarJiri Olsa <jolsa@kernel.org>
Link: https://lore.kernel.org/r/20240806230319.869734-1-andrii@kernel.orgSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent b4406e10
......@@ -35,6 +35,8 @@ __weak void backtrace_symbols_fd(void *const *buffer, int size, int fd)
dprintf(fd, "<backtrace not supported>\n");
}
int env_verbosity = 0;
static bool verbose(void)
{
return env.verbosity > VERBOSE_NONE;
......@@ -973,6 +975,7 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state)
return -EINVAL;
}
}
env_verbosity = env->verbosity;
if (verbose()) {
if (setenv("SELFTESTS_VERBOSE", "1", 1) == -1) {
......
......@@ -96,6 +96,8 @@ struct test_state {
FILE *stdout_saved;
};
extern int env_verbosity;
struct test_env {
struct test_selector test_selector;
struct test_selector subtest_selector;
......
......@@ -10,6 +10,8 @@
#include <pthread.h>
#include <unistd.h>
#include <linux/perf_event.h>
#include <linux/fs.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include "trace_helpers.h"
#include <linux/limits.h>
......@@ -244,29 +246,91 @@ int kallsyms_find(const char *sym, unsigned long long *addr)
return err;
}
#ifdef PROCMAP_QUERY
int env_verbosity __weak = 0;
int procmap_query(int fd, const void *addr, __u32 query_flags, size_t *start, size_t *offset, int *flags)
{
char path_buf[PATH_MAX], build_id_buf[20];
struct procmap_query q;
int err;
memset(&q, 0, sizeof(q));
q.size = sizeof(q);
q.query_flags = query_flags;
q.query_addr = (__u64)addr;
q.vma_name_addr = (__u64)path_buf;
q.vma_name_size = sizeof(path_buf);
q.build_id_addr = (__u64)build_id_buf;
q.build_id_size = sizeof(build_id_buf);
err = ioctl(fd, PROCMAP_QUERY, &q);
if (err < 0) {
err = -errno;
if (err == -ENOTTY)
return -EOPNOTSUPP; /* ioctl() not implemented yet */
if (err == -ENOENT)
return -ESRCH; /* vma not found */
return err;
}
if (env_verbosity >= 1) {
printf("VMA FOUND (addr %08lx): %08lx-%08lx %c%c%c%c %08lx %02x:%02x %ld %s (build ID: %s, %d bytes)\n",
(long)addr, (long)q.vma_start, (long)q.vma_end,
(q.vma_flags & PROCMAP_QUERY_VMA_READABLE) ? 'r' : '-',
(q.vma_flags & PROCMAP_QUERY_VMA_WRITABLE) ? 'w' : '-',
(q.vma_flags & PROCMAP_QUERY_VMA_EXECUTABLE) ? 'x' : '-',
(q.vma_flags & PROCMAP_QUERY_VMA_SHARED) ? 's' : 'p',
(long)q.vma_offset, q.dev_major, q.dev_minor, (long)q.inode,
q.vma_name_size ? path_buf : "",
q.build_id_size ? "YES" : "NO",
q.build_id_size);
}
*start = q.vma_start;
*offset = q.vma_offset;
*flags = q.vma_flags;
return 0;
}
#else
int procmap_query(int fd, const void *addr, size_t *start, size_t *offset, int *flags)
{
return -EOPNOTSUPP;
}
#endif
ssize_t get_uprobe_offset(const void *addr)
{
size_t start, end, base;
char buf[256];
bool found = false;
size_t start, base, end;
FILE *f;
char buf[256];
int err, flags;
f = fopen("/proc/self/maps", "r");
if (!f)
return -errno;
while (fscanf(f, "%zx-%zx %s %zx %*[^\n]\n", &start, &end, buf, &base) == 4) {
if (buf[2] == 'x' && (uintptr_t)addr >= start && (uintptr_t)addr < end) {
found = true;
break;
/* requested executable VMA only */
err = procmap_query(fileno(f), addr, PROCMAP_QUERY_VMA_EXECUTABLE, &start, &base, &flags);
if (err == -EOPNOTSUPP) {
bool found = false;
while (fscanf(f, "%zx-%zx %s %zx %*[^\n]\n", &start, &end, buf, &base) == 4) {
if (buf[2] == 'x' && (uintptr_t)addr >= start && (uintptr_t)addr < end) {
found = true;
break;
}
}
if (!found) {
fclose(f);
return -ESRCH;
}
} else if (err) {
fclose(f);
return err;
}
fclose(f);
if (!found)
return -ESRCH;
#if defined(__powerpc64__) && defined(_CALL_ELF) && _CALL_ELF == 2
#define OP_RT_RA_MASK 0xffff0000UL
......@@ -307,15 +371,25 @@ ssize_t get_rel_offset(uintptr_t addr)
size_t start, end, offset;
char buf[256];
FILE *f;
int err, flags;
f = fopen("/proc/self/maps", "r");
if (!f)
return -errno;
while (fscanf(f, "%zx-%zx %s %zx %*[^\n]\n", &start, &end, buf, &offset) == 4) {
if (addr >= start && addr < end) {
fclose(f);
return (size_t)addr - start + offset;
err = procmap_query(fileno(f), (const void *)addr, 0, &start, &offset, &flags);
if (err == 0) {
fclose(f);
return (size_t)addr - start + offset;
} else if (err != -EOPNOTSUPP) {
fclose(f);
return err;
} else if (err) {
while (fscanf(f, "%zx-%zx %s %zx %*[^\n]\n", &start, &end, buf, &offset) == 4) {
if (addr >= start && addr < end) {
fclose(f);
return (size_t)addr - start + offset;
}
}
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment