From patchwork Wed Aug 14 18:54:17 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrii Nakryiko X-Patchwork-Id: 13763845 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 kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id C493DC3DA4A for ; Wed, 14 Aug 2024 18:55:00 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 57A386B00A3; Wed, 14 Aug 2024 14:55:00 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 529196B00A4; Wed, 14 Aug 2024 14:55:00 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 3A3736B00A5; Wed, 14 Aug 2024 14:55:00 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0015.hostedemail.com [216.40.44.15]) by kanga.kvack.org (Postfix) with ESMTP id 1D3446B00A3 for ; Wed, 14 Aug 2024 14:55:00 -0400 (EDT) Received: from smtpin07.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay07.hostedemail.com (Postfix) with ESMTP id 9AE4D160EB4 for ; Wed, 14 Aug 2024 18:54:59 +0000 (UTC) X-FDA: 82451753118.07.0196111 Received: from sin.source.kernel.org (sin.source.kernel.org [145.40.73.55]) by imf23.hostedemail.com (Postfix) with ESMTP id 4A4E0140024 for ; Wed, 14 Aug 2024 18:54:56 +0000 (UTC) Authentication-Results: imf23.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=jY4efrO+; dmarc=pass (policy=none) header.from=kernel.org; spf=pass (imf23.hostedemail.com: domain of andrii@kernel.org designates 145.40.73.55 as permitted sender) smtp.mailfrom=andrii@kernel.org ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1723661644; a=rsa-sha256; cv=none; b=zpsFoIHkesP3YBOcN/tNDP2KjUmN4DkrWkq+Gp8tDfPYbvTnG+DSmMP+uLtaXWVQEZoMgC tDWjAhmbhOPwmvHdq6IhkwPz7ZfnDSU/5NgegjiDfTRDSAu4m0F2pudsq813A8EwIep2HH 2wDaR3A/0GXO8UYT0p8yd2ybsGhQTD4= ARC-Authentication-Results: i=1; imf23.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=jY4efrO+; dmarc=pass (policy=none) header.from=kernel.org; spf=pass (imf23.hostedemail.com: domain of andrii@kernel.org designates 145.40.73.55 as permitted sender) smtp.mailfrom=andrii@kernel.org ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1723661644; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=1aETl6fo73R2hGtR8v+/aiQ2Xs81hCN3zXqYhLiMx0o=; b=dBI+xKQoY6jP/o/0N1CNBzGSEiCpF1+Bpru6AL3byNBZNRoPSBILBcgL50gWg8ap8qI+8I OmwPpJv0t0sUW+NR+2BiL9KO5UaOHZP6nv4EGYX1PT04q5fuBNKq9aNg7JCkVcUaIewq1G K4bVsNqj+gJWpycYMoiYWIfyQQuZ9GU= Received: from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58]) by sin.source.kernel.org (Postfix) with ESMTP id B7861CE1ADE; Wed, 14 Aug 2024 18:54:54 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id AC1BFC116B1; Wed, 14 Aug 2024 18:54:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1723661693; bh=hAHRGfhHTT27DNY5NeOM9zG7twQB27NQc7Kw1Yx1Eb8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=jY4efrO+owN7jqjsqntSS7+Qfa6KzvkD4aIvlgKxbRk7nxONoD+rfkKb/Tr/sPf7m tFobHLjJ4nzHBkw+lEkcK7AUjVLLv9CWuHnCu4zk4v2Pn9k1bErLXthB0xAOuN0EO2 3cWx9Uy2msd/MvkNjkIETZAfe4f/V2COPJCxS9sGl2sZgGST48n9aV+qA+xjHckWwD JLI/ppzjQCcZU2US1L96q+pPHwlWvw2RqTYPwVZ5M0uG9yaiC8rzjIBr9F7FeaN6S1 PEvz+2qA4U51RcNrYkZsjNQL6NisZhgb4IgQ2mqQGHEmrNnPoUNwJDH7Wsxu+AjMjM N8019AtW2Y5Tg== From: Andrii Nakryiko To: bpf@vger.kernel.org Cc: linux-mm@kvack.org, akpm@linux-foundation.org, adobriyan@gmail.com, shakeel.butt@linux.dev, hannes@cmpxchg.org, ak@linux.intel.com, osandov@osandov.com, song@kernel.org, jannh@google.com, linux-fsdevel@vger.kernel.org, willy@infradead.org, Andrii Nakryiko Subject: [PATCH v6 bpf-next 10/10] selftests/bpf: add build ID tests Date: Wed, 14 Aug 2024 11:54:17 -0700 Message-ID: <20240814185417.1171430-11-andrii@kernel.org> X-Mailer: git-send-email 2.43.5 In-Reply-To: <20240814185417.1171430-1-andrii@kernel.org> References: <20240814185417.1171430-1-andrii@kernel.org> MIME-Version: 1.0 X-Rspamd-Queue-Id: 4A4E0140024 X-Rspam-User: X-Rspamd-Server: rspam05 X-Stat-Signature: 8qdnt1winsf3595uut43qmjbmorjgq7q X-HE-Tag: 1723661696-449597 X-HE-Meta: U2FsdGVkX1/1ys5jseGscl0NqeS7liXIIVtWATRZ+SBdcg2SQbxHpWcLh29dwPFHmUarn+7aeFGQNu4Woj3+EeteiJQPnrsWGmISlO1/UrWRijXPLGFK7UMdWYpCqUPGskoYphB6zFJoTtbf0q1XGhjr74hDePU16a7/11kXPKG8emuGgLG9omNcHNs0W6tu4pePnXmOEEx7lKQbOjKI+iHG23bHsLAoqMA2Lg8ORxYFaEvIqnIRKr/7Fl6g5YaBlWnOOATrzIR3jdRRzv+Wgc3uioJexh5aDNzGreLvtWpcB+dNTTUuK1FcWzEndQez5+IrCdVoiCk/hDc5ADyhRuZPNnDIvkFnIOVj9gKiKLJP28tZEfmp44nRfsodrfUku0uiHit2sefgTtvfNZM7nWT9n3la3atUUOfrpmZlF1xthTusSZ3e/AE4NcJniXb47kYMjgzVnhXohvj28fSL80Qok3KbWrpL+cgMTTmfXt5UejQoixYyHUB3ik0UDwtsd60djeZQzmxc5IbmlzKKFlaICniZ+gOKAOdzK+TjKhNUTtjNQDwW9fF6y/udNyaUMob2Xx334y6y2sxug0MSJFutm2ihkxVP3uxXpH3HSjlbdPZcr1BePPQLolKZN7NZ7BQbwDEfxX2q5GFDJvy/amCtM6hGDO/2BjXNZ1xV2xkOFYk+LPCyUg7zklDUv9s1uRFr4PlCZ+ubSoNErVf9DwQbZaqZ89JPeBFEiuUPBy+pHJSR3WHybaO1Dn6ZO5WuqQ1rGX9scdR5pKrE9jH5d8ke0Ux6NoCdDIp16ly4sSutjqcS7KzQRWQwNKgsu55cHDn/YvjbYrwFOjA47FQ6rMvD3jRSSr2gr71xEVKCpZ7sj/giYqAasSSRg3EG3YUiw9gdNQFdsDBUSkk52U/D89NgqiWMTkbo1bAFQ0CDF4tweEKylwhcxs3umdnFODNUC4u7ykb9eMtQaLPMrwG tAy7noQS b5NYfcn03cIdeHNwJAoSLCwLzde7685WG6iWF99GQWQhsZRrS88N0fbpafHOttz1qsHBuYUCSJg/oIR2lIv2o83iJjJgNz0irl2MsgblaA9SRDcPz9QGvcJje9sz86GMA8N2cx9ZgM4M/NRybuWItrfGh933y2FdlfofVtyWyRiwAX/xcYYDLmdr9kzbT6b6B9rieOA3adcD48oKd1UW4dvCKSRID12fyHmu0S8qN0dkWRSM= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: Add a new set of tests validating behavior of capturing stack traces with build ID. We extend uprobe_multi target binary with ability to trigger uprobe (so that we can capture stack traces from it), but also we allow to force build ID data to be either resident or non-resident in memory (see also a comment about quirks of MADV_PAGEOUT). That way we can validate that in non-sleepable context we won't get build ID (as expected), but with sleepable uprobes we will get that build ID regardless of it being physically present in memory. Also, we add a small add-on linker script which reorders .note.gnu.build-id section and puts it after (big) .text section, putting build ID data outside of the very first page of ELF file. This will test all the relaxations we did in build ID parsing logic in kernel thanks to freader abstraction. Signed-off-by: Andrii Nakryiko Acked-by: Eduard Zingerman --- tools/testing/selftests/bpf/Makefile | 5 +- .../selftests/bpf/prog_tests/build_id.c | 118 ++++++++++++++++++ .../selftests/bpf/progs/test_build_id.c | 31 +++++ tools/testing/selftests/bpf/uprobe_multi.c | 41 ++++++ tools/testing/selftests/bpf/uprobe_multi.ld | 11 ++ 5 files changed, 204 insertions(+), 2 deletions(-) create mode 100644 tools/testing/selftests/bpf/prog_tests/build_id.c create mode 100644 tools/testing/selftests/bpf/progs/test_build_id.c create mode 100644 tools/testing/selftests/bpf/uprobe_multi.ld diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 7e4b107b37b4..e47d983d2694 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -787,9 +787,10 @@ $(OUTPUT)/veristat: $(OUTPUT)/veristat.o # Linking uprobe_multi can fail due to relocation overflows on mips. $(OUTPUT)/uprobe_multi: CFLAGS += $(if $(filter mips, $(ARCH)),-mxgot) -$(OUTPUT)/uprobe_multi: uprobe_multi.c +$(OUTPUT)/uprobe_multi: uprobe_multi.c uprobe_multi.ld $(call msg,BINARY,,$@) - $(Q)$(CC) $(CFLAGS) -O0 $(LDFLAGS) $^ $(LDLIBS) -o $@ + $(Q)$(CC) $(CFLAGS) -Wl,-T,uprobe_multi.ld -O0 $(LDFLAGS) \ + $(filter-out %.ld,$^) $(LDLIBS) -o $@ EXTRA_CLEAN := $(SCRATCH_DIR) $(HOST_SCRATCH_DIR) \ prog_tests/tests.h map_tests/tests.h verifier/tests.h \ diff --git a/tools/testing/selftests/bpf/prog_tests/build_id.c b/tools/testing/selftests/bpf/prog_tests/build_id.c new file mode 100644 index 000000000000..aec9c8d6bc96 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/build_id.c @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */ +#include + +#include "test_build_id.skel.h" + +static char build_id[BPF_BUILD_ID_SIZE]; +static int build_id_sz; + +static void print_stack(struct bpf_stack_build_id *stack, int frame_cnt) +{ + int i, j; + + for (i = 0; i < frame_cnt; i++) { + printf("FRAME #%02d: ", i); + switch (stack[i].status) { + case BPF_STACK_BUILD_ID_EMPTY: + printf("\n"); + break; + case BPF_STACK_BUILD_ID_VALID: + printf("BUILD ID = "); + for (j = 0; j < BPF_BUILD_ID_SIZE; j++) + printf("%02hhx", (unsigned)stack[i].build_id[j]); + printf(" OFFSET = %llx", (unsigned long long)stack[i].offset); + break; + case BPF_STACK_BUILD_ID_IP: + printf("IP = %llx", (unsigned long long)stack[i].ip); + break; + default: + printf("UNEXPECTED STATUS %d ", stack[i].status); + break; + } + printf("\n"); + } +} + +static void subtest_nofault(bool build_id_resident) +{ + struct test_build_id *skel; + struct bpf_stack_build_id *stack; + int frame_cnt; + + skel = test_build_id__open_and_load(); + if (!ASSERT_OK_PTR(skel, "skel_open")) + return; + + skel->links.uprobe_nofault = bpf_program__attach(skel->progs.uprobe_nofault); + if (!ASSERT_OK_PTR(skel->links.uprobe_nofault, "link")) + goto cleanup; + + if (build_id_resident) + ASSERT_OK(system("./uprobe_multi uprobe-paged-in"), "trigger_uprobe"); + else + ASSERT_OK(system("./uprobe_multi uprobe-paged-out"), "trigger_uprobe"); + + if (!ASSERT_GT(skel->bss->res_nofault, 0, "res")) + goto cleanup; + + stack = skel->bss->stack_nofault; + frame_cnt = skel->bss->res_nofault / sizeof(struct bpf_stack_build_id); + if (env.verbosity >= VERBOSE_NORMAL) + print_stack(stack, frame_cnt); + + if (build_id_resident) { + ASSERT_EQ(stack[0].status, BPF_STACK_BUILD_ID_VALID, "build_id_status"); + ASSERT_EQ(memcmp(stack[0].build_id, build_id, build_id_sz), 0, "build_id_match"); + } else { + ASSERT_EQ(stack[0].status, BPF_STACK_BUILD_ID_IP, "build_id_status"); + } + +cleanup: + test_build_id__destroy(skel); +} + +static void subtest_sleepable(void) +{ + struct test_build_id *skel; + struct bpf_stack_build_id *stack; + int frame_cnt; + + skel = test_build_id__open_and_load(); + if (!ASSERT_OK_PTR(skel, "skel_open")) + return; + + skel->links.uprobe_sleepable = bpf_program__attach(skel->progs.uprobe_sleepable); + if (!ASSERT_OK_PTR(skel->links.uprobe_sleepable, "link")) + goto cleanup; + + /* force build ID to not be paged in */ + ASSERT_OK(system("./uprobe_multi uprobe-paged-out"), "trigger_uprobe"); + + if (!ASSERT_GT(skel->bss->res_sleepable, 0, "res")) + goto cleanup; + + stack = skel->bss->stack_sleepable; + frame_cnt = skel->bss->res_sleepable / sizeof(struct bpf_stack_build_id); + if (env.verbosity >= VERBOSE_NORMAL) + print_stack(stack, frame_cnt); + + ASSERT_EQ(stack[0].status, BPF_STACK_BUILD_ID_VALID, "build_id_status"); + ASSERT_EQ(memcmp(stack[0].build_id, build_id, build_id_sz), 0, "build_id_match"); + +cleanup: + test_build_id__destroy(skel); +} + +void serial_test_build_id(void) +{ + build_id_sz = read_build_id("uprobe_multi", build_id, sizeof(build_id)); + ASSERT_EQ(build_id_sz, BPF_BUILD_ID_SIZE, "parse_build_id"); + + if (test__start_subtest("nofault-paged-out")) + subtest_nofault(false /* not resident */); + if (test__start_subtest("nofault-paged-in")) + subtest_nofault(true /* resident */); + if (test__start_subtest("sleepable")) + subtest_sleepable(); +} diff --git a/tools/testing/selftests/bpf/progs/test_build_id.c b/tools/testing/selftests/bpf/progs/test_build_id.c new file mode 100644 index 000000000000..32ce59f9aa27 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_build_id.c @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */ + +#include "vmlinux.h" +#include + +struct bpf_stack_build_id stack_sleepable[128]; +int res_sleepable; + +struct bpf_stack_build_id stack_nofault[128]; +int res_nofault; + +SEC("uprobe.multi/./uprobe_multi:uprobe") +int uprobe_nofault(struct pt_regs *ctx) +{ + res_nofault = bpf_get_stack(ctx, stack_nofault, sizeof(stack_nofault), + BPF_F_USER_STACK | BPF_F_USER_BUILD_ID); + + return 0; +} + +SEC("uprobe.multi.s/./uprobe_multi:uprobe") +int uprobe_sleepable(struct pt_regs *ctx) +{ + res_sleepable = bpf_get_stack(ctx, stack_sleepable, sizeof(stack_sleepable), + BPF_F_USER_STACK | BPF_F_USER_BUILD_ID); + + return 0; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/uprobe_multi.c b/tools/testing/selftests/bpf/uprobe_multi.c index 7ffa563ffeba..c7828b13e5ff 100644 --- a/tools/testing/selftests/bpf/uprobe_multi.c +++ b/tools/testing/selftests/bpf/uprobe_multi.c @@ -2,8 +2,21 @@ #include #include +#include +#include +#include +#include #include +#ifndef MADV_POPULATE_READ +#define MADV_POPULATE_READ 22 +#endif + +int __attribute__((weak)) uprobe(void) +{ + return 0; +} + #define __PASTE(a, b) a##b #define PASTE(a, b) __PASTE(a, b) @@ -75,6 +88,30 @@ static int usdt(void) return 0; } +extern char build_id_start[]; +extern char build_id_end[]; + +int __attribute__((weak)) trigger_uprobe(bool build_id_resident) +{ + int page_sz = sysconf(_SC_PAGESIZE); + void *addr; + + /* page-align build ID start */ + addr = (void *)((uintptr_t)&build_id_start & ~(page_sz - 1)); + + /* to guarantee MADV_PAGEOUT work reliably, we need to ensure that + * memory range is mapped into current process, so we unconditionally + * do MADV_POPULATE_READ, and then MADV_PAGEOUT, if necessary + */ + madvise(addr, page_sz, MADV_POPULATE_READ); + if (!build_id_resident) + madvise(addr, page_sz, MADV_PAGEOUT); + + (void)uprobe(); + + return 0; +} + int main(int argc, char **argv) { if (argc != 2) @@ -84,6 +121,10 @@ int main(int argc, char **argv) return bench(); if (!strcmp("usdt", argv[1])) return usdt(); + if (!strcmp("uprobe-paged-out", argv[1])) + return trigger_uprobe(false /* page-out build ID */); + if (!strcmp("uprobe-paged-in", argv[1])) + return trigger_uprobe(true /* page-in build ID */); error: fprintf(stderr, "usage: %s \n", argv[0]); diff --git a/tools/testing/selftests/bpf/uprobe_multi.ld b/tools/testing/selftests/bpf/uprobe_multi.ld new file mode 100644 index 000000000000..a2e94828bc8c --- /dev/null +++ b/tools/testing/selftests/bpf/uprobe_multi.ld @@ -0,0 +1,11 @@ +SECTIONS +{ + . = ALIGN(4096); + .note.gnu.build-id : { *(.note.gnu.build-id) } + . = ALIGN(4096); +} +INSERT AFTER .text; + +build_id_start = ADDR(.note.gnu.build-id); +build_id_end = ADDR(.note.gnu.build-id) + SIZEOF(.note.gnu.build-id); +