diff options
Diffstat (limited to 'tools')
50 files changed, 2024 insertions, 485 deletions
diff --git a/tools/gpio/gpio-event-mon.c b/tools/gpio/gpio-event-mon.c index 90c3155f05b1..cacd66ad7926 100644 --- a/tools/gpio/gpio-event-mon.c +++ b/tools/gpio/gpio-event-mon.c @@ -148,6 +148,7 @@ void print_usage(void) " -s Set line as open source\n" " -r Listen for rising edges\n" " -f Listen for falling edges\n" + " -w Report the wall-clock time for events\n" " -b <n> Debounce the line with period n microseconds\n" " [-c <n>] Do <n> loops (optional, infinite loop if not stated)\n" " -? This helptext\n" @@ -173,7 +174,7 @@ int main(int argc, char **argv) memset(&config, 0, sizeof(config)); config.flags = GPIO_V2_LINE_FLAG_INPUT; - while ((c = getopt(argc, argv, "c:n:o:b:dsrf?")) != -1) { + while ((c = getopt(argc, argv, "c:n:o:b:dsrfw?")) != -1) { switch (c) { case 'c': loops = strtoul(optarg, NULL, 10); @@ -204,6 +205,9 @@ int main(int argc, char **argv) case 'f': config.flags |= GPIO_V2_LINE_FLAG_EDGE_FALLING; break; + case 'w': + config.flags |= GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME; + break; case '?': print_usage(); return -1; diff --git a/tools/gpio/lsgpio.c b/tools/gpio/lsgpio.c index 5a05a454d0c9..c61d061247e1 100644 --- a/tools/gpio/lsgpio.c +++ b/tools/gpio/lsgpio.c @@ -65,6 +65,10 @@ struct gpio_flag flagnames[] = { .name = "bias-disabled", .mask = GPIO_V2_LINE_FLAG_BIAS_DISABLED, }, + { + .name = "clock-realtime", + .mask = GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME, + }, }; static void print_attributes(struct gpio_v2_line_info *info) diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index 54188ee16c48..4e2450964517 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -1499,17 +1499,16 @@ sub dodie { my $log_file; if (defined($opt{"LOG_FILE"})) { - my $whence = 0; # beginning of file - my $pos = $test_log_start; + my $whence = 2; # End of file + my $log_size = tell LOG; + my $size = $log_size - $test_log_start; if (defined($mail_max_size)) { - my $log_size = tell LOG; - $log_size -= $test_log_start; - if ($log_size > $mail_max_size) { - $whence = 2; # end of file - $pos = - $mail_max_size; + if ($size > $mail_max_size) { + $size = $mail_max_size; } } + my $pos = - $size; $log_file = "$tmpdir/log"; open (L, "$opt{LOG_FILE}") or die "Can't open $opt{LOG_FILE} to read)"; open (O, "> $tmpdir/log") or die "Can't open $tmpdir/log\n"; @@ -4253,7 +4252,12 @@ sub do_send_mail { $mail_command =~ s/\$SUBJECT/$subject/g; $mail_command =~ s/\$MESSAGE/$message/g; - run_command $mail_command; + my $ret = run_command $mail_command; + if (!$ret && defined($file)) { + # try again without the file + $message .= "\n\n*** FAILED TO SEND LOG ***\n\n"; + do_send_email($subject, $message); + } } sub send_email { diff --git a/tools/testing/selftests/core/close_range_test.c b/tools/testing/selftests/core/close_range_test.c index 87e16d65d9d7..73eb29c916d1 100644 --- a/tools/testing/selftests/core/close_range_test.c +++ b/tools/testing/selftests/core/close_range_test.c @@ -17,7 +17,23 @@ #include "../clone3/clone3_selftests.h" #ifndef __NR_close_range -#define __NR_close_range -1 + #if defined __alpha__ + #define __NR_close_range 546 + #elif defined _MIPS_SIM + #if _MIPS_SIM == _MIPS_SIM_ABI32 /* o32 */ + #define __NR_close_range (436 + 4000) + #endif + #if _MIPS_SIM == _MIPS_SIM_NABI32 /* n32 */ + #define __NR_close_range (436 + 6000) + #endif + #if _MIPS_SIM == _MIPS_SIM_ABI64 /* n64 */ + #define __NR_close_range (436 + 5000) + #endif + #elif defined __ia64__ + #define __NR_close_range (436 + 1024) + #else + #define __NR_close_range 436 + #endif #endif #ifndef CLOSE_RANGE_UNSHARE @@ -102,7 +118,7 @@ TEST(close_range_unshare) int i, ret, status; pid_t pid; int open_fds[101]; - struct clone_args args = { + struct __clone_args args = { .flags = CLONE_FILES, .exit_signal = SIGCHLD, }; @@ -191,7 +207,7 @@ TEST(close_range_unshare_capped) int i, ret, status; pid_t pid; int open_fds[101]; - struct clone_args args = { + struct __clone_args args = { .flags = CLONE_FILES, .exit_signal = SIGCHLD, }; @@ -241,7 +257,7 @@ TEST(close_range_cloexec) fd = open("/dev/null", O_RDONLY); ASSERT_GE(fd, 0) { if (errno == ENOENT) - XFAIL(return, "Skipping test since /dev/null does not exist"); + SKIP(return, "Skipping test since /dev/null does not exist"); } open_fds[i] = fd; @@ -250,9 +266,9 @@ TEST(close_range_cloexec) ret = sys_close_range(1000, 1000, CLOSE_RANGE_CLOEXEC); if (ret < 0) { if (errno == ENOSYS) - XFAIL(return, "close_range() syscall not supported"); + SKIP(return, "close_range() syscall not supported"); if (errno == EINVAL) - XFAIL(return, "close_range() doesn't support CLOSE_RANGE_CLOEXEC"); + SKIP(return, "close_range() doesn't support CLOSE_RANGE_CLOEXEC"); } /* Ensure the FD_CLOEXEC bit is set also with a resource limit in place. */ @@ -297,5 +313,258 @@ TEST(close_range_cloexec) } } +TEST(close_range_cloexec_unshare) +{ + int i, ret; + int open_fds[101]; + struct rlimit rlimit; + + for (i = 0; i < ARRAY_SIZE(open_fds); i++) { + int fd; + + fd = open("/dev/null", O_RDONLY); + ASSERT_GE(fd, 0) { + if (errno == ENOENT) + SKIP(return, "Skipping test since /dev/null does not exist"); + } + + open_fds[i] = fd; + } + + ret = sys_close_range(1000, 1000, CLOSE_RANGE_CLOEXEC); + if (ret < 0) { + if (errno == ENOSYS) + SKIP(return, "close_range() syscall not supported"); + if (errno == EINVAL) + SKIP(return, "close_range() doesn't support CLOSE_RANGE_CLOEXEC"); + } + + /* Ensure the FD_CLOEXEC bit is set also with a resource limit in place. */ + ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &rlimit)); + rlimit.rlim_cur = 25; + ASSERT_EQ(0, setrlimit(RLIMIT_NOFILE, &rlimit)); + + /* Set close-on-exec for two ranges: [0-50] and [75-100]. */ + ret = sys_close_range(open_fds[0], open_fds[50], + CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_UNSHARE); + ASSERT_EQ(0, ret); + ret = sys_close_range(open_fds[75], open_fds[100], + CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_UNSHARE); + ASSERT_EQ(0, ret); + + for (i = 0; i <= 50; i++) { + int flags = fcntl(open_fds[i], F_GETFD); + + EXPECT_GT(flags, -1); + EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC); + } + + for (i = 51; i <= 74; i++) { + int flags = fcntl(open_fds[i], F_GETFD); + + EXPECT_GT(flags, -1); + EXPECT_EQ(flags & FD_CLOEXEC, 0); + } + + for (i = 75; i <= 100; i++) { + int flags = fcntl(open_fds[i], F_GETFD); + + EXPECT_GT(flags, -1); + EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC); + } + + /* Test a common pattern. */ + ret = sys_close_range(3, UINT_MAX, + CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_UNSHARE); + for (i = 0; i <= 100; i++) { + int flags = fcntl(open_fds[i], F_GETFD); + + EXPECT_GT(flags, -1); + EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC); + } +} + +/* + * Regression test for syzbot+96cfd2b22b3213646a93@syzkaller.appspotmail.com + */ +TEST(close_range_cloexec_syzbot) +{ + int fd1, fd2, fd3, flags, ret, status; + pid_t pid; + struct __clone_args args = { + .flags = CLONE_FILES, + .exit_signal = SIGCHLD, + }; + + /* Create a huge gap in the fd table. */ + fd1 = open("/dev/null", O_RDWR); + EXPECT_GT(fd1, 0); + + fd2 = dup2(fd1, 1000); + EXPECT_GT(fd2, 0); + + pid = sys_clone3(&args, sizeof(args)); + ASSERT_GE(pid, 0); + + if (pid == 0) { + ret = sys_close_range(3, ~0U, CLOSE_RANGE_CLOEXEC); + if (ret) + exit(EXIT_FAILURE); + + /* + * We now have a private file descriptor table and all + * our open fds should still be open but made + * close-on-exec. + */ + flags = fcntl(fd1, F_GETFD); + EXPECT_GT(flags, -1); + EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC); + + flags = fcntl(fd2, F_GETFD); + EXPECT_GT(flags, -1); + EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC); + + fd3 = dup2(fd1, 42); + EXPECT_GT(fd3, 0); + + /* + * Duplicating the file descriptor must remove the + * FD_CLOEXEC flag. + */ + flags = fcntl(fd3, F_GETFD); + EXPECT_GT(flags, -1); + EXPECT_EQ(flags & FD_CLOEXEC, 0); + + exit(EXIT_SUCCESS); + } + + EXPECT_EQ(waitpid(pid, &status, 0), pid); + EXPECT_EQ(true, WIFEXITED(status)); + EXPECT_EQ(0, WEXITSTATUS(status)); + + /* + * We had a shared file descriptor table before along with requesting + * close-on-exec so the original fds must not be close-on-exec. + */ + flags = fcntl(fd1, F_GETFD); + EXPECT_GT(flags, -1); + EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC); + + flags = fcntl(fd2, F_GETFD); + EXPECT_GT(flags, -1); + EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC); + + fd3 = dup2(fd1, 42); + EXPECT_GT(fd3, 0); + + flags = fcntl(fd3, F_GETFD); + EXPECT_GT(flags, -1); + EXPECT_EQ(flags & FD_CLOEXEC, 0); + + EXPECT_EQ(close(fd1), 0); + EXPECT_EQ(close(fd2), 0); + EXPECT_EQ(close(fd3), 0); +} + +/* + * Regression test for syzbot+96cfd2b22b3213646a93@syzkaller.appspotmail.com + */ +TEST(close_range_cloexec_unshare_syzbot) +{ + int i, fd1, fd2, fd3, flags, ret, status; + pid_t pid; + struct __clone_args args = { + .flags = CLONE_FILES, + .exit_signal = SIGCHLD, + }; + + /* + * Create a huge gap in the fd table. When we now call + * CLOSE_RANGE_UNSHARE with a shared fd table and and with ~0U as upper + * bound the kernel will only copy up to fd1 file descriptors into the + * new fd table. If the kernel is buggy and doesn't handle + * CLOSE_RANGE_CLOEXEC correctly it will not have copied all file + * descriptors and we will oops! + * + * On a buggy kernel this should immediately oops. But let's loop just + * to be sure. + */ + fd1 = open("/dev/null", O_RDWR); + EXPECT_GT(fd1, 0); + + fd2 = dup2(fd1, 1000); + EXPECT_GT(fd2, 0); + + for (i = 0; i < 100; i++) { + + pid = sys_clone3(&args, sizeof(args)); + ASSERT_GE(pid, 0); + + if (pid == 0) { + ret = sys_close_range(3, ~0U, CLOSE_RANGE_UNSHARE | + CLOSE_RANGE_CLOEXEC); + if (ret) + exit(EXIT_FAILURE); + + /* + * We now have a private file descriptor table and all + * our open fds should still be open but made + * close-on-exec. + */ + flags = fcntl(fd1, F_GETFD); + EXPECT_GT(flags, -1); + EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC); + + flags = fcntl(fd2, F_GETFD); + EXPECT_GT(flags, -1); + EXPECT_EQ(flags & FD_CLOEXEC, FD_CLOEXEC); + + fd3 = dup2(fd1, 42); + EXPECT_GT(fd3, 0); + + /* + * Duplicating the file descriptor must remove the + * FD_CLOEXEC flag. + */ + flags = fcntl(fd3, F_GETFD); + EXPECT_GT(flags, -1); + EXPECT_EQ(flags & FD_CLOEXEC, 0); + + EXPECT_EQ(close(fd1), 0); + EXPECT_EQ(close(fd2), 0); + EXPECT_EQ(close(fd3), 0); + + exit(EXIT_SUCCESS); + } + + EXPECT_EQ(waitpid(pid, &status, 0), pid); + EXPECT_EQ(true, WIFEXITED(status)); + EXPECT_EQ(0, WEXITSTATUS(status)); + } + + /* + * We created a private file descriptor table before along with + * requesting close-on-exec so the original fds must not be + * close-on-exec. + */ + flags = fcntl(fd1, F_GETFD); + EXPECT_GT(flags, -1); + EXPECT_EQ(flags & FD_CLOEXEC, 0); + + flags = fcntl(fd2, F_GETFD); + EXPECT_GT(flags, -1); + EXPECT_EQ(flags & FD_CLOEXEC, 0); + + fd3 = dup2(fd1, 42); + EXPECT_GT(fd3, 0); + + flags = fcntl(fd3, F_GETFD); + EXPECT_GT(flags, -1); + EXPECT_EQ(flags & FD_CLOEXEC, 0); + + EXPECT_EQ(close(fd1), 0); + EXPECT_EQ(close(fd2), 0); + EXPECT_EQ(close(fd3), 0); +} TEST_HARNESS_MAIN diff --git a/tools/testing/selftests/filesystems/epoll/epoll_wakeup_test.c b/tools/testing/selftests/filesystems/epoll/epoll_wakeup_test.c index 8f82f99f7748..ad7fabd575f9 100644 --- a/tools/testing/selftests/filesystems/epoll/epoll_wakeup_test.c +++ b/tools/testing/selftests/filesystems/epoll/epoll_wakeup_test.c @@ -1,6 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 #define _GNU_SOURCE +#include <asm/unistd.h> +#include <linux/time_types.h> #include <poll.h> #include <unistd.h> #include <assert.h> @@ -21,6 +23,19 @@ struct epoll_mtcontext pthread_t waiter; }; +#ifndef __NR_epoll_pwait2 +#define __NR_epoll_pwait2 -1 +#endif + +static inline int sys_epoll_pwait2(int fd, struct epoll_event *events, + int maxevents, + const struct __kernel_timespec *timeout, + const sigset_t *sigset, size_t sigsetsize) +{ + return syscall(__NR_epoll_pwait2, fd, events, maxevents, timeout, + sigset, sigsetsize); +} + static void signal_handler(int signum) { } @@ -3377,4 +3392,61 @@ TEST(epoll61) close(ctx.evfd); } +/* Equivalent to basic test epoll1, but exercising epoll_pwait2. */ +TEST(epoll62) +{ + int efd; + int sfd[2]; + struct epoll_event e; + + ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, sfd), 0); + + efd = epoll_create(1); + ASSERT_GE(efd, 0); + + e.events = EPOLLIN; + ASSERT_EQ(epoll_ctl(efd, EPOLL_CTL_ADD, sfd[0], &e), 0); + + ASSERT_EQ(write(sfd[1], "w", 1), 1); + + EXPECT_EQ(sys_epoll_pwait2(efd, &e, 1, NULL, NULL, 0), 1); + EXPECT_EQ(sys_epoll_pwait2(efd, &e, 1, NULL, NULL, 0), 1); + + close(efd); + close(sfd[0]); + close(sfd[1]); +} + +/* Epoll_pwait2 basic timeout test. */ +TEST(epoll63) +{ + const int cfg_delay_ms = 10; + unsigned long long tdiff; + struct __kernel_timespec ts; + int efd; + int sfd[2]; + struct epoll_event e; + + ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, sfd), 0); + + efd = epoll_create(1); + ASSERT_GE(efd, 0); + + e.events = EPOLLIN; + ASSERT_EQ(epoll_ctl(efd, EPOLL_CTL_ADD, sfd[0], &e), 0); + + ts.tv_sec = 0; + ts.tv_nsec = cfg_delay_ms * 1000 * 1000; + + tdiff = msecs(); + EXPECT_EQ(sys_epoll_pwait2(efd, &e, 1, &ts, NULL, 0), 0); + tdiff = msecs() - tdiff; + + EXPECT_GE(tdiff, cfg_delay_ms); + + close(efd); + close(sfd[0]); + close(sfd[1]); +} + TEST_HARNESS_MAIN diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore index 7a2c242b7152..ce8f4ad39684 100644 --- a/tools/testing/selftests/kvm/.gitignore +++ b/tools/testing/selftests/kvm/.gitignore @@ -14,17 +14,17 @@ /x86_64/set_sregs_test /x86_64/smm_test /x86_64/state_test -/x86_64/user_msr_test -/x86_64/vmx_preemption_timer_test /x86_64/svm_vmcall_test /x86_64/sync_regs_test +/x86_64/tsc_msrs_test +/x86_64/userspace_msr_exit_test /x86_64/vmx_apic_access_test /x86_64/vmx_close_while_nested_test /x86_64/vmx_dirty_log_test +/x86_64/vmx_preemption_timer_test /x86_64/vmx_set_nested_state_test /x86_64/vmx_tsc_adjust_test /x86_64/xss_msr_test -/clear_dirty_log_test /demand_paging_test /dirty_log_test /dirty_log_perf_test diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index 3d14ef77755e..c7ca4faba272 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -36,7 +36,7 @@ endif LIBKVM = lib/assert.c lib/elf.c lib/io.c lib/kvm_util.c lib/sparsebit.c lib/test_util.c LIBKVM_x86_64 = lib/x86_64/processor.c lib/x86_64/vmx.c lib/x86_64/svm.c lib/x86_64/ucall.c lib/x86_64/handlers.S LIBKVM_aarch64 = lib/aarch64/processor.c lib/aarch64/ucall.c -LIBKVM_s390x = lib/s390x/processor.c lib/s390x/ucall.c +LIBKVM_s390x = lib/s390x/processor.c lib/s390x/ucall.c lib/s390x/diag318_test_handler.c TEST_GEN_PROGS_x86_64 = x86_64/cr4_cpuid_sync_test TEST_GEN_PROGS_x86_64 += x86_64/evmcs_test @@ -50,6 +50,7 @@ TEST_GEN_PROGS_x86_64 += x86_64/state_test TEST_GEN_PROGS_x86_64 += x86_64/vmx_preemption_timer_test TEST_GEN_PROGS_x86_64 += x86_64/svm_vmcall_test TEST_GEN_PROGS_x86_64 += x86_64/sync_regs_test +TEST_GEN_PROGS_x86_64 += x86_64/userspace_msr_exit_test TEST_GEN_PROGS_x86_64 += x86_64/vmx_apic_access_test TEST_GEN_PROGS_x86_64 += x86_64/vmx_close_while_nested_test TEST_GEN_PROGS_x86_64 += x86_64/vmx_dirty_log_test @@ -58,7 +59,6 @@ TEST_GEN_PROGS_x86_64 += x86_64/vmx_tsc_adjust_test TEST_GEN_PROGS_x86_64 += x86_64/xss_msr_test TEST_GEN_PROGS_x86_64 += x86_64/debug_regs TEST_GEN_PROGS_x86_64 += x86_64/tsc_msrs_test -TEST_GEN_PROGS_x86_64 += x86_64/user_msr_test TEST_GEN_PROGS_x86_64 += demand_paging_test TEST_GEN_PROGS_x86_64 += dirty_log_test TEST_GEN_PROGS_x86_64 += dirty_log_perf_test @@ -70,6 +70,7 @@ TEST_GEN_PROGS_aarch64 += aarch64/get-reg-list TEST_GEN_PROGS_aarch64 += aarch64/get-reg-list-sve TEST_GEN_PROGS_aarch64 += demand_paging_test TEST_GEN_PROGS_aarch64 += dirty_log_test +TEST_GEN_PROGS_aarch64 += dirty_log_perf_test TEST_GEN_PROGS_aarch64 += kvm_create_max_vcpus TEST_GEN_PROGS_aarch64 += set_memory_region_test TEST_GEN_PROGS_aarch64 += steal_time diff --git a/tools/testing/selftests/kvm/aarch64/get-reg-list.c b/tools/testing/selftests/kvm/aarch64/get-reg-list.c index 33218a395d9f..486932164cf2 100644 --- a/tools/testing/selftests/kvm/aarch64/get-reg-list.c +++ b/tools/testing/selftests/kvm/aarch64/get-reg-list.c @@ -42,12 +42,16 @@ #define for_each_reg(i) \ for ((i) = 0; (i) < reg_list->n; ++(i)) +#define for_each_reg_filtered(i) \ + for_each_reg(i) \ + if (!filter_reg(reg_list->reg[i])) + #define for_each_missing_reg(i) \ for ((i) = 0; (i) < blessed_n; ++(i)) \ if (!find_reg(reg_list->reg, reg_list->n, blessed_reg[i])) #define for_each_new_reg(i) \ - for ((i) = 0; (i) < reg_list->n; ++(i)) \ + for_each_reg_filtered(i) \ if (!find_reg(blessed_reg, blessed_n, reg_list->reg[i])) @@ -57,6 +61,18 @@ static __u64 base_regs[], vregs[], sve_regs[], rejects_set[]; static __u64 base_regs_n, vregs_n, sve_regs_n, rejects_set_n; static __u64 *blessed_reg, blessed_n; +static bool filter_reg(__u64 reg) +{ + /* + * DEMUX register presence depends on the host's CLIDR_EL1. + * This means there's no set of them that we can bless. + */ + if ((reg & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX) + return true; + + return false; +} + static bool find_reg(__u64 regs[], __u64 nr_regs, __u64 reg) { int i; @@ -325,7 +341,7 @@ int main(int ac, char **av) struct kvm_vcpu_init init = { .target = -1, }; int new_regs = 0, missing_regs = 0, i; int failed_get = 0, failed_set = 0, failed_reject = 0; - bool print_list = false, fixup_core_regs = false; + bool print_list = false, print_filtered = false, fixup_core_regs = false; struct kvm_vm *vm; __u64 *vec_regs; @@ -336,8 +352,10 @@ int main(int ac, char **av) fixup_core_regs = true; else if (strcmp(av[i], "--list") == 0) print_list = true; + else if (strcmp(av[i], "--list-filtered") == 0) + print_filtered = true; else - fprintf(stderr, "Ignoring unknown option: %s\n", av[i]); + TEST_FAIL("Unknown option: %s\n", av[i]); } vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES, O_RDWR); @@ -350,10 +368,14 @@ int main(int ac, char **av) if (fixup_core_regs) core_reg_fixup(); - if (print_list) { + if (print_list || print_filtered) { putchar('\n'); - for_each_reg(i) - print_reg(reg_list->reg[i]); + for_each_reg(i) { + __u64 id = reg_list->reg[i]; + if ((print_list && !filter_reg(id)) || + (print_filtered && filter_reg(id))) + print_reg(id); + } putchar('\n'); return 0; } @@ -458,6 +480,8 @@ int main(int ac, char **av) /* * The current blessed list was primed with the output of kernel version * v4.15 with --core-reg-fixup and then later updated with new registers. + * + * The blessed |