From patchwork Tue Jul 9 20:42:45 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrii Nakryiko X-Patchwork-Id: 13728515 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 86AE4C2BD09 for ; Tue, 9 Jul 2024 20:43:31 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 264896B00A9; Tue, 9 Jul 2024 16:43:31 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 2149A6B00AA; Tue, 9 Jul 2024 16:43:31 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 0DC366B00AB; Tue, 9 Jul 2024 16:43:31 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0016.hostedemail.com [216.40.44.16]) by kanga.kvack.org (Postfix) with ESMTP id E41956B00A9 for ; Tue, 9 Jul 2024 16:43:30 -0400 (EDT) Received: from smtpin06.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay01.hostedemail.com (Postfix) with ESMTP id 885801C3817 for ; Tue, 9 Jul 2024 20:43:30 +0000 (UTC) X-FDA: 82321389780.06.3176A27 Received: from sin.source.kernel.org (sin.source.kernel.org [145.40.73.55]) by imf09.hostedemail.com (Postfix) with ESMTP id 45F3B14000F for ; Tue, 9 Jul 2024 20:43:27 +0000 (UTC) Authentication-Results: imf09.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=syDbLbkt; spf=pass (imf09.hostedemail.com: domain of andrii@kernel.org designates 145.40.73.55 as permitted sender) smtp.mailfrom=andrii@kernel.org; dmarc=pass (policy=none) header.from=kernel.org ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1720557779; 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=ago8UIKakUbx1w8xAWzA9HsZh/OpRn31XYZP6bTJG1M=; b=sctRf7QjOBUdXIXho8WjRcQHRJQBMAKiyuY8bovmb+ZBEnY52eV1ZD4g9EzWcubFokwDFO JgFmY6j1JZ3bGKb80ra5/GPqwaK85tmWb8nBdN+tj139ZSM+uuhZIPBSKf4izb01eA3xNh aWYm4nQIR9iJY3ALzEKWa8zBa86qgCc= ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1720557779; a=rsa-sha256; cv=none; b=L9SaUxs5Mb9f3c5iJhss2B1F0ibbs1KDmN9GWO9xTruqwhw4GdTwebUGYDavsABcaET7NX fWJ211ilmQsnQ/+mFY6MIKvse91RN9A2J1NyaoPKVZGku8+xji3PUTYePcGfThDDafqZ9z 8rA/K0lrg5ffCndJxfFF3/FUCR3Dwk8= ARC-Authentication-Results: i=1; imf09.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=syDbLbkt; spf=pass (imf09.hostedemail.com: domain of andrii@kernel.org designates 145.40.73.55 as permitted sender) smtp.mailfrom=andrii@kernel.org; dmarc=pass (policy=none) header.from=kernel.org Received: from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58]) by sin.source.kernel.org (Postfix) with ESMTP id 97F74CE12E8; Tue, 9 Jul 2024 20:43:25 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id A4F7CC4AF0C; Tue, 9 Jul 2024 20:43:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1720557804; bh=9f5XHZsGbbTDw89JnaMKZvno0TqLABUY0GcFo3N7UXE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=syDbLbkt/rrCN4xxHQDcqceSI4SU1mZuUzAg+FrJFKGOoHJXVVk6BzxxQyb5GfLdL ZdlePWJkPYUdWGBzoxMzOJLkTdDKgD1fKTAB0mWnHiDYsGwDHhMAqF5yTgX4sQWwqN Ml/mCbxu/ix7FsISj++JBIuFWxWemRvDWSc0MoplmJRQ00xdJzhicceBv7ZwpLJbjt io7XO6p0oxkXU+a6cfxADVumNjJtRseGb6Ijx/hwRLm0z0O8Xag8AJdCh19G8MjIDr Iqe47hAejf67sDNAe6tHVX4UC8ShaLWzm+gpDTYwvTAHFtiiiBCuW1yjSfWbQb//zy nJIuTmmXk9GkA== 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, Andrii Nakryiko Subject: [PATCH bpf-next 10/10] selftests/bpf: add build ID tests Date: Tue, 9 Jul 2024 13:42:45 -0700 Message-ID: <20240709204245.3847811-11-andrii@kernel.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240709204245.3847811-1-andrii@kernel.org> References: <20240709204245.3847811-1-andrii@kernel.org> MIME-Version: 1.0 X-Rspamd-Queue-Id: 45F3B14000F X-Stat-Signature: gei83nuzuqrzt3mzrodpjo99e9qqxka6 X-Rspamd-Server: rspam09 X-Rspam-User: X-HE-Tag: 1720557807-603135 X-HE-Meta: U2FsdGVkX18KfLt1AqM1ZufXuDMLX1phyT+kd6Jz9VLQFCF8oTdKv3ehFj2L8kUOsR0D9P8Z/E6rVxPdIsr3yv+fQGjJqTheN8aKvJTyw5ZdLewWzgyDUdDJj7zyI2/q0DYOCxUSrLIv8YJ+oEYaWttkc9AnRNobCJkFJdoackuNUZ0OmugDIp2CfILTIifgzlbj0fc2RE1NFNrSiz/ZDv6yvhOcWUuGnlSmE8UlaF2qtEwzJERG0Cu4rcFlrObqDfMnrOzTzLhDMYt+Sf+GtSqnDA7wateE7PGzA+rJbXyk/pOIP2VRcZzdR4wtShuJ9OJh+H67xzkMn7KW1JOSEcd7YegwwNOON+zZjJeCa38SukNjnWt4hfH/x7jd5XrOcSkGSD3ad2o1vm5oy6FTHnR2+a7+ddIPO1/HUbDDkuKmmClaS3t0iRvou7s/DHUPSFsCO4nCRUvy7WAAaqR+a+ejw5hMe8TuqUCVVboIzUZYuPcOFiHmmHjGDmoU6ZxlFdLhvJ9yV7VF981+l+unPb4mfdH0U5KITaKbxyXSFVlhEarQjNr/TPxfL1XqRYmFHN+lGBmIyzPabgNpZ8qO3tWL2egZ3F/6gkP9Pd5JlvX+/OcO9/S26nOy4T03YCX2V7ip8BUapz5mm8/3kzT2z8ZTJ7edC9W7xSLWsMrzPlYDeyzbdD2YskVWuni40in9l6qe/d9UMk8ztnjkflOUbQHG9VtpF3LK7cM88ILGXJHBat//XNxTENQpTdtD2ziOv6X7Cpd+fW2oPvLaKMHDaejxaOjBPQA/qFfcYc1adogrDDwGmBStBxmHlGB51jzTqRMK3WsZr9Ln64cAyvONbD4J4C78lqKOXAtrYOTJnOgWnZgSyPCsKQIYKaVUxt7efOuHGa2Rt3HVM+DSNYTVwNf604fvt1nP3hV/vE2p3nbJ5u81GLYJm0CMEG58cKlXUkU1mmCVTIE5ewTRab2 H+Lp0QDi c6QdPiOTKdWL1cnQkBbIgmY/SLCOQFTQMTeS1jGHjRvbukd0HfgVBo3OdTqmJ9fXNTLK5EXqUI9C9iI3fOrZPbaxuANDn67l3QkPVN9aLORjm0suexy2GsUzWD5AaPlsWQvJbWBER75HIhghOQmk/pBlcS3J2nPf6/YYpiY3muTaRSQgr+ysO3pwHKxlYHtMX1TTQBmkgQomM7o8GVcYUA0K1vdqYIHKYnNDfdauxknTlo8s= 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. 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 --- 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 | 34 +++++ tools/testing/selftests/bpf/uprobe_multi.ld | 11 ++ 5 files changed, 197 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 e0b3887b3d2d..45f67e822f49 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -762,9 +762,10 @@ $(OUTPUT)/veristat: $(OUTPUT)/veristat.o $(call msg,BINARY,,$@) $(Q)$(CC) $(CFLAGS) $(LDFLAGS) $(filter %.a %.o,$^) $(LDLIBS) -o $@ -$(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..8e6d3603be61 --- /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 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..edd7ef3bd5cd 100644 --- a/tools/testing/selftests/bpf/uprobe_multi.c +++ b/tools/testing/selftests/bpf/uprobe_multi.c @@ -2,6 +2,10 @@ #include #include +#include +#include +#include +#include #include #define __PASTE(a, b) a##b @@ -75,6 +79,32 @@ static int usdt(void) return 0; } +int __attribute__((weak)) uprobe(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)); + + if (build_id_resident) + madvise(addr, page_sz, MADV_POPULATE_READ); + else + madvise(addr, page_sz, MADV_PAGEOUT); + + (void)uprobe(); + + return 0; +} + int main(int argc, char **argv) { if (argc != 2) @@ -84,6 +114,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); +