#include <common/compat/time.hpp>
#include <common/error.hpp>
+#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <poll.h>
int lttng_opt_quiet, lttng_opt_verbose, lttng_opt_mi;
static void run_working_cases(FILE *validation_output_file);
-static void pselect_invalid_fd(FILE *validation_output_file);
static void test_ppoll_big(FILE *validation_output_file);
-static void ppoll_fds_buffer_overflow(FILE *validation_output_file);
static void pselect_invalid_pointer(FILE *validation_output_file);
+static void pselect_invalid_fd(FILE *validation_output_file);
static void ppoll_fds_ulong_max(FILE *validation_output_file);
+static void ppoll_fds_buffer_overflow(FILE *validation_output_file);
static void epoll_pwait_invalid_pointer(FILE *validation_output_file);
static void epoll_pwait_int_max(FILE *validation_output_file);
static void ppoll_concurrent_write(FILE *validation_output_file);
static void epoll_pwait_concurrent_munmap(FILE *validation_output_file);
-using test_case_cb = void (*)(FILE *);
+typedef void (*test_case_cb)(FILE *output_file);
namespace {
const struct test_case {
test_case_cb run;
bool produces_validation_info;
int timeout;
+ const char *name;
+ const char *description;
} test_cases[] = {
- { .run = run_working_cases, .produces_validation_info = true, .timeout = -1 },
- { .run = run_working_cases, .produces_validation_info = true, .timeout = 1 },
- { .run = pselect_invalid_fd, .produces_validation_info = false, .timeout = 0 },
- { .run = test_ppoll_big, .produces_validation_info = false, .timeout = 0 },
- { .run = ppoll_fds_buffer_overflow, .produces_validation_info = false, .timeout = 0 },
- { .run = pselect_invalid_pointer, .produces_validation_info = false, .timeout = 0 },
- { .run = ppoll_fds_ulong_max, .produces_validation_info = false, .timeout = 0 },
- { .run = epoll_pwait_invalid_pointer, .produces_validation_info = true, .timeout = 0 },
- { .run = epoll_pwait_int_max, .produces_validation_info = true, .timeout = 0 },
- { .run = ppoll_concurrent_write, .produces_validation_info = false, .timeout = 0 },
- { .run = epoll_pwait_concurrent_munmap, .produces_validation_info = true, .timeout = 0 },
+ { .run = run_working_cases,
+ .produces_validation_info = true,
+ .timeout = -1,
+ .name = "working_cases",
+ .description =
+ "Working cases for select, pselect6, poll, ppoll and epoll, waiting for input" },
+ { .run = run_working_cases,
+ .produces_validation_info = true,
+ .timeout = 1,
+ .name = "working_cases_timeout",
+ .description = "Timeout cases (1ms) for select, pselect6, poll, ppoll and epoll" },
+ { .run = test_ppoll_big,
+ .produces_validation_info = false,
+ .timeout = 0,
+ .name = "ppoll_big",
+ .description = "ppoll with " XSTR(MAX_FDS) " FDs" },
+ { .run = epoll_pwait_invalid_pointer,
+ .produces_validation_info = true,
+ .timeout = 0,
+ .name = "epoll_pwait_invalid_pointer",
+ .description = "epoll_pwait with an invalid pointer, waits for input" },
+ { .run = epoll_pwait_int_max,
+ .produces_validation_info = true,
+ .timeout = 0,
+ .name = "epoll_pwait_int_max",
+ .description = "epoll_pwait with maxevents set to INT_MAX waits for input" },
+ { .run = ppoll_concurrent_write,
+ .produces_validation_info = false,
+ .timeout = 0,
+ .name = "ppoll_concurrent_write",
+ .description =
+ "ppoll with concurrent updates of the structure from user-space, stress test (3000 iterations) waits for input + timeout 1ms" },
+ { .run = epoll_pwait_concurrent_munmap,
+ .produces_validation_info = true,
+ .timeout = 0,
+ .name = "epoll_pwait_concurrent_munmap",
+ .description =
+ "epoll_pwait with concurrent munmap of the buffer from user-space, should randomly segfault, run multiple times, waits for input + timeout 1ms" },
+ { .run = pselect_invalid_pointer,
+ .produces_validation_info = false,
+ .timeout = 0,
+ .name = "pselect_invalid_pointer",
+ .description = "pselect with an invalid pointer, waits for input" },
+ { .run = pselect_invalid_fd,
+ .produces_validation_info = false,
+ .timeout = 0,
+ .name = "pselect_invalid_fd",
+ .description = "pselect with an invalid fd" },
+ { .run = ppoll_fds_ulong_max,
+ .produces_validation_info = false,
+ .timeout = 0,
+ .name = "ppoll_fds_ulong_max",
+ .description = "ppoll with ulong_max fds, waits for input" },
+ { .run = ppoll_fds_buffer_overflow,
+ .produces_validation_info = false,
+ .timeout = 0,
+ .name = "ppoll_fds_buffer_overflow",
+ .description = "ppoll buffer overflow, should segfault, waits for input" },
};
struct ppoll_thread_data {
};
} /* namespace */
-static void test_select_big()
+static void test_select_big(void)
{
fd_set rfds, wfds, exfds;
struct timeval tv;
if (timeout > 0) {
ret = select(fd2 + 1, &rfds, &wfds, &exfds, &tv);
} else {
- ret = select(fd2 + 1, &rfds, &wfds, &exfds, nullptr);
+ ret = select(fd2 + 1, &rfds, &wfds, &exfds, NULL);
}
if (ret == -1) {
return;
}
-static void test_pselect()
+static void test_pselect_generic(long int syscall_id)
{
fd_set rfds;
struct timespec tv;
tv.tv_nsec = timeout * MSEC_PER_NSEC;
if (timeout > 0) {
- ret = pselect(1, &rfds, nullptr, nullptr, &tv, nullptr);
+ ret = syscall(syscall_id, 1, &rfds, NULL, NULL, &tv, NULL);
} else {
- ret = pselect(1, &rfds, nullptr, nullptr, nullptr, nullptr);
+ ret = syscall(syscall_id, 1, &rfds, NULL, NULL, NULL, NULL);
}
if (ret == -1) {
}
}
-static void test_select()
+static void test_pselect(void)
+{
+ test_pselect_generic(SYS_pselect6);
+}
+
+static void test_select(void)
{
fd_set rfds;
struct timeval tv;
tv.tv_usec = timeout * MSEC_PER_USEC;
if (timeout > 0) {
- ret = select(1, &rfds, nullptr, nullptr, &tv);
+ ret = select(1, &rfds, NULL, NULL, &tv);
} else {
- ret = select(1, &rfds, nullptr, nullptr, nullptr);
+ ret = select(1, &rfds, NULL, NULL, NULL);
}
if (ret == -1) {
}
}
-static void test_poll()
+static void test_poll(void)
{
struct pollfd ufds[NB_FD];
char buf[BUF_SIZE];
}
}
-static void test_ppoll()
+static void test_ppoll_generic(long int syscall_id)
{
struct pollfd ufds[NB_FD];
char buf[BUF_SIZE];
if (timeout > 0) {
ts.tv_sec = 0;
ts.tv_nsec = timeout * MSEC_PER_NSEC;
- ret = ppoll(ufds, 1, &ts, nullptr);
+ ret = syscall(syscall_id, ufds, 1, &ts, NULL);
} else {
- ret = ppoll(ufds, 1, nullptr, nullptr);
+ ret = syscall(syscall_id, ufds, 1, NULL, NULL);
}
if (ret < 0) {
}
}
+static void test_ppoll(void)
+{
+ test_ppoll_generic(SYS_ppoll);
+}
+
static void test_ppoll_big(FILE *validation_output_file __attribute__((unused)))
{
struct pollfd ufds[MAX_FDS];
ufds[i].events = POLLIN | POLLPRI;
}
- ret = ppoll(ufds, MAX_FDS, nullptr, nullptr);
+ ret = ppoll(ufds, MAX_FDS, NULL, NULL);
if (ret < 0) {
PERROR("ppoll");
}
if (timeout > 0) {
- ret = epoll_pwait(epollfd, &epoll_event, 1, timeout, nullptr);
+ ret = epoll_pwait(epollfd, &epoll_event, 1, timeout, NULL);
} else {
- ret = epoll_pwait(epollfd, &epoll_event, 1, -1, nullptr);
+ ret = epoll_pwait(epollfd, &epoll_event, 1, -1, NULL);
}
if (ret == 1) {
wait_fd = pipe_fds[0];
}
test_select();
+#ifdef sys_pselect6_time64
+ test_pselect_time64();
+#else
test_pselect();
+#endif /* sys_pselect6_time64 */
test_select_big();
test_poll();
test_ppoll();
+#ifdef sys_ppoll_time64
+ test_ppoll_time64();
+#else
+ test_ppoll();
+#endif /* sys_ppoll_time64 */
- ret = fprintf(validation_output_file, "{ \"pid\": %i", getpid());
+ ret = fprintf(validation_output_file, "{\"pid\": %i", getpid());
if (ret < 0) {
PERROR("Failed to write pid to test validation file");
goto end;
}
/*
- * Ask for 100 FDs in a buffer for allocated for only 1 FD, should
- * segfault (eventually with a "*** stack smashing detected ***" message).
- * The event should contain an array of 100 FDs filled with garbage.
+ * Ask for ULONG_MAX FDs in a buffer for allocated for only 1 FD, should
+ * cleanly fail with a "Invalid argument".
+ * The event should contain an empty array of FDs and overflow = 1.
*/
-static void ppoll_fds_buffer_overflow(FILE *validation_output_file __attribute__((unused)))
+static void generic_ppoll_fds_ulong_max(long int syscall_id)
{
struct pollfd ufds[NB_FD];
char buf[BUF_SIZE];
ufds[0].fd = wait_fd;
ufds[0].events = POLLIN | POLLPRI;
- ret = syscall(SYS_ppoll, ufds, 100, NULL, NULL);
-
+ /* ppoll and/or ppoll_time64 are used, depending on platform support. */
+ ret = syscall(syscall_id, ufds, ULONG_MAX, NULL, NULL);
if (ret < 0) {
- PERROR("ppoll");
+ /* Expected error. */
} else if (ret > 0) {
ret = read(wait_fd, buf, BUF_SIZE);
if (ret < 0) {
- PERROR("[ppoll] read");
+ PERROR("Failed to read from wait file descriptor");
}
}
}
/*
- * Ask for ULONG_MAX FDs in a buffer for allocated for only 1 FD, should
- * cleanly fail with a "Invalid argument".
- * The event should contain an empty array of FDs and overflow = 1.
+ * Ask for 100 FDs in a buffer for allocated for only 1 FD, should
+ * segfault (eventually with a "*** stack smashing detected ***" message).
+ * The event should contain an array of 100 FDs filled with garbage.
*/
-static void ppoll_fds_ulong_max(FILE *validation_output_file __attribute__((unused)))
+static void generic_ppoll_fds_buffer_overflow(long int syscall_id)
{
struct pollfd ufds[NB_FD];
char buf[BUF_SIZE];
ufds[0].fd = wait_fd;
ufds[0].events = POLLIN | POLLPRI;
- ret = syscall(SYS_ppoll, ufds, ULONG_MAX, NULL, NULL);
+ /* ppoll and/or ppoll_time64 are used, depending on platform support. */
+ ret = syscall(syscall_id, ufds, 100, NULL, NULL);
if (ret < 0) {
- /* Expected error. */
+ PERROR("Failed to wait using ppoll/ppoll_time64");
} else if (ret > 0) {
ret = read(wait_fd, buf, BUF_SIZE);
if (ret < 0) {
- PERROR("[ppoll] read");
+ PERROR("Failed to read from wait file descriptor");
}
}
}
+static void ppoll_fds_ulong_max(FILE *validation_output_file __attribute__((unused)))
+{
+#ifdef SYS_ppoll_time64
+ generic_ppoll_fds_ulong_max(SYS_ppoll_time64);
+#else
+ generic_ppoll_fds_ulong_max(SYS_ppoll);
+#endif /* SYS_ppoll_time64 */
+}
+
+static void ppoll_fds_buffer_overflow(FILE *validation_output_file __attribute__((unused)))
+{
+#ifdef SYS_ppoll_time64
+ generic_ppoll_fds_buffer_overflow(SYS_ppoll_time64);
+#else
+ generic_ppoll_fds_buffer_overflow(SYS_ppoll);
+#endif /* SYS_ppoll_time64 */
+}
+
/*
* Pass an invalid file descriptor to pselect6(). The syscall should return
* -EBADF. The recorded event should contain a "ret = -EBADF (-9)".
*/
-static void pselect_invalid_fd(FILE *validation_output_file __attribute__((unused)))
+static void generic_invalid_fd(long int syscall_id)
{
fd_set rfds;
int ret;
*/
fd = open("/dev/null", O_RDONLY);
if (fd == -1) {
- PERROR("open");
+ PERROR("Failed to open /dev/null");
goto error;
}
ret = close(fd);
if (ret == -1) {
- PERROR("close");
+ PERROR("Failed to close /dev/null file descriptor");
goto error;
}
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
- ret = syscall(SYS_pselect6, fd + 1, &rfds, NULL, NULL, NULL, NULL);
+ ret = syscall(syscall_id, fd + 1, &rfds, NULL, NULL, NULL, NULL);
if (ret == -1) {
/* Expected error. */
} else if (ret) {
ret = read(wait_fd, buf, BUF_SIZE);
if (ret < 0) {
- PERROR("[pselect] read");
+ PERROR("Failed to read from wait file descriptor");
}
}
error:
* Invalid pointer as writefds, should output a ppoll event
* with 0 FDs.
*/
-static void pselect_invalid_pointer(FILE *validation_output_file __attribute__((unused)))
+static void generic_invalid_pointer(int syscall_id)
{
fd_set rfds;
int ret;
FD_ZERO(&rfds);
FD_SET(wait_fd, &rfds);
- ret = syscall(SYS_pselect6, 1, &rfds, (fd_set *) invalid, NULL, NULL, NULL);
+ ret = syscall(syscall_id, 1, &rfds, (fd_set *) invalid, NULL, NULL, NULL);
if (ret == -1) {
/* Expected error. */
} else if (ret) {
ret = read(wait_fd, buf, BUF_SIZE);
if (ret < 0) {
- PERROR("[pselect] read");
+ PERROR("Failed to read from wait file descriptor");
}
}
}
+static void pselect_invalid_fd(FILE *validation_output_file __attribute__((unused)))
+{
+#ifdef SYS_pselect6_time64
+ generic_invalid_fd(SYS_pselect6_time64);
+#else
+ generic_invalid_fd(SYS_pselect6);
+#endif /* SYS_pselect6_time64 */
+}
+
+/*
+ * Invalid pointer as writefds, should output a ppoll event
+ * with 0 FDs.
+ */
+static void pselect_invalid_pointer(FILE *validation_output_file __attribute__((unused)))
+{
+#ifdef SYS_pselect6_time64
+ generic_invalid_pointer(SYS_pselect6_time64);
+#else
+ generic_invalid_pointer(SYS_pselect6);
+#endif /* SYS_pselect6_time64 */
+}
+
/*
* Pass an invalid pointer to epoll_pwait, should fail with
* "Bad address", the event returns 0 FDs.
goto end;
}
- ret = fprintf(
- validation_output_file, "{ \"epollfd\": %i, \"pid\": %i }", epollfd, getpid());
+ ret = fprintf(validation_output_file, "{\"epollfd\": %i, \"pid\": %i }", epollfd, getpid());
if (ret < 0) {
PERROR("[epoll_pwait] Failed to write test validation output");
goto error;
goto end;
}
- ret = fprintf(
- validation_output_file, "{ \"epollfd\": %i, \"pid\": %i }", epollfd, getpid());
+ ret = fprintf(validation_output_file, "{\"epollfd\": %i, \"pid\": %i }", epollfd, getpid());
if (ret < 0) {
PERROR("[epoll_pwait] Failed to write test validation output");
goto error;
usleep(100);
}
- return nullptr;
+ return NULL;
}
static void do_ppoll(int *fds, struct pollfd *ufds)
ufds[i].events = POLLIN | POLLPRI;
}
- ret = ppoll(ufds, MAX_FDS, &ts, nullptr);
+ ret = ppoll(ufds, MAX_FDS, &ts, NULL);
if (ret < 0) {
PERROR("ppoll");
thread_data.value = value;
stop_thread = 0;
- ret = pthread_create(&writer, nullptr, &ppoll_writer, (void *) &thread_data);
+ ret = pthread_create(&writer, NULL, &ppoll_writer, (void *) &thread_data);
if (ret != 0) {
fprintf(stderr, "[error] pthread_create\n");
goto end;
do_ppoll(fds, ufds);
}
stop_thread = 1;
- ret = pthread_join(writer, nullptr);
+ ret = pthread_join(writer, NULL);
if (ret) {
fprintf(stderr, "[error] pthread_join\n");
goto end;
static void *epoll_pwait_writer(void *addr)
{
- srand(time(nullptr));
+ srand(time(NULL));
while (!stop_thread) {
usleep(rand() % 30);
munmap(addr, MAX_FDS * sizeof(struct epoll_event));
}
- return nullptr;
+ return NULL;
}
/*
goto end;
}
- ret = fprintf(
- validation_output_file, "{ \"epollfd\": %i, \"pid\": %i }", epollfd, getpid());
+ ret = fprintf(validation_output_file, "{\"epollfd\": %i, \"pid\": %i }", epollfd, getpid());
if (ret < 0) {
PERROR("[epoll_pwait] Failed to write test validation output");
goto error;
}
- epoll_event = (struct epoll_event *) mmap(nullptr,
+ epoll_event = (struct epoll_event *) mmap(NULL,
MAX_FDS * sizeof(struct epoll_event),
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS,
}
}
stop_thread = 0;
- ret = pthread_create(&writer, nullptr, &epoll_pwait_writer, (void *) epoll_event);
+ ret = pthread_create(&writer, NULL, &epoll_pwait_writer, (void *) epoll_event);
if (ret != 0) {
fprintf(stderr, "[error] pthread_create\n");
goto error_unmap;
}
- ret = epoll_pwait(epollfd, epoll_event, 1, 1, nullptr);
+ ret = epoll_pwait(epollfd, epoll_event, 1, 1, NULL);
if (ret == 1) {
ret = read(wait_fd, buf, BUF_SIZE);
}
stop_thread = 1;
- ret = pthread_join(writer, nullptr);
+ ret = pthread_join(writer, NULL);
if (ret) {
fprintf(stderr, "[error] pthread_join\n");
goto error_unmap;
return;
}
-static void print_list()
+static void print_list(void)
+{
+ printf("Test list (-t X):\n");
+
+ for (size_t test_id = 0; test_id < ARRAY_SIZE(test_cases); test_id++) {
+ printf("\t%zu: %s - %s\n",
+ test_id + 1,
+ test_cases[test_id].name,
+ test_cases[test_id].description);
+ }
+}
+
+static void print_test_syscalls(void)
{
- fprintf(stderr, "Test list (-t X):\n");
- fprintf(stderr,
- "\t1: Working cases for select, pselect6, poll, ppoll "
- "and epoll, waiting for input\n");
- fprintf(stderr,
- "\t2: Timeout cases (1ms) for select, pselect6, poll, "
- "ppoll and epoll\n");
- fprintf(stderr, "\t3: pselect with an invalid fd\n");
- fprintf(stderr, "\t4: ppoll with %d FDs\n", MAX_FDS);
- fprintf(stderr,
- "\t5: ppoll buffer overflow, should segfault, waits "
- "for input\n");
- fprintf(stderr,
- "\t6: pselect with an invalid pointer, waits for "
- "input\n");
- fprintf(stderr, "\t7: ppoll with ulong_max fds, waits for input\n");
- fprintf(stderr,
- "\t8: epoll_pwait with an invalid pointer, waits for "
- "input\n");
- fprintf(stderr,
- "\t9: epoll_pwait with maxevents set to INT_MAX, "
- "waits for input\n");
- fprintf(stderr,
- "\t10: ppoll with concurrent updates of the structure "
- "from user-space, stress test (3000 iterations), "
- "waits for input + timeout 1ms\n");
- fprintf(stderr,
- "\t11: epoll_pwait with concurrent munmap of the buffer "
- "from user-space, should randomly segfault, run "
- "multiple times, waits for input + timeout 1ms\n");
+ const char *supported_syscalls[] = {
+#ifdef SYS_select
+ "select",
+#endif
+#if defined SYS_pselect6_time64 && defined SYS_pselect6
+ "pselect6",
+ "pselect6_time32",
+#elif defined SYS_pselect6_time32 ^ defined SYS_pselect6
+ "pselect6",
+#endif /* SYS_pselect6_time64 && defined SYS_pselect6 */
+#ifdef SYS_poll
+ "poll",
+#endif
+#if defined SYS_ppoll && defined SYS_ppoll_time64
+ "ppoll",
+ "ppoll_time32",
+#elif defined SYS_ppoll ^ defined SYS_ppoll_time64
+ "ppoll",
+#endif /* defined SYS_ppoll && defined SYS_ppoll_time64 */
+#ifdef SYS_epoll_ctl
+ "epoll_ctl",
+#endif
+#ifdef SYS_epoll_wait
+ "epoll_wait",
+#endif
+#ifdef SYS_epoll_pwait
+ "epoll_pwait",
+#endif
+ };
+
+ for (size_t i = 0; i < ARRAY_SIZE(supported_syscalls); i++) {
+ fputs(supported_syscalls[i], stdout);
+ fputs(i != ARRAY_SIZE(supported_syscalls) - 1 ? "," : "\n", stdout);
+ }
}
int main(int argc, const char **argv)
{
- int c, ret, test = -1;
+ int c, ret;
+ const char *test_name;
poptContext optCon;
struct rlimit open_lim;
- FILE *test_validation_output_file = nullptr;
- const char *test_validation_output_file_path = nullptr;
+ FILE *test_validation_output_file = NULL;
+ const char *test_validation_output_file_path = NULL;
struct poptOption optionsTable[] = {
- { "test", 't', POPT_ARG_INT, &test, 0, "Test to run", nullptr },
- { "list", 'l', 0, nullptr, 'l', "List of tests (-t X)", nullptr },
+ { "test", 't', POPT_ARG_STRING, &test_name, 0, "Name of test to run", NULL },
+ { "list-tests", 'l', 0, 0, 'l', "List tests (-t X)", NULL },
+ { "list-supported-test-syscalls",
+ 's',
+ 0,
+ 0,
+ 's',
+ "List supported test syscalls",
+ NULL },
{ "validation-file",
'o',
POPT_ARG_STRING,
&test_validation_output_file_path,
0,
"Test case output",
- nullptr },
- POPT_AUTOHELP{ nullptr, 0, 0, nullptr, 0, nullptr, nullptr }
+ NULL },
+ POPT_AUTOHELP{ NULL, 0, 0, NULL, 0, NULL, NULL }
};
const struct test_case *test_case;
+ size_t test_case_id;
- optCon = poptGetContext(nullptr, argc, argv, optionsTable, 0);
+ optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
if (argc < 2) {
poptPrintUsage(optCon, stderr, 0);
case 'l':
print_list();
goto end;
+ case 's':
+ print_test_syscalls();
+ goto end;
}
}
* for the validation, disabling the buffering on the validation file
* works.
*/
- setbuf(test_validation_output_file, nullptr);
+ setbuf(test_validation_output_file, NULL);
wait_fd = STDIN_FILENO;
/* Test case id is 1-based. */
- if (test < 1 || test > ARRAY_SIZE(test_cases)) {
+ for (test_case_id = 0; test_case_id < ARRAY_SIZE(test_cases); test_case_id++) {
+ if (!strcmp(test_cases[test_case_id].name, test_name)) {
+ break;
+ }
+ }
+
+ if (test_case_id == ARRAY_SIZE(test_cases)) {
poptPrintUsage(optCon, stderr, 0);
ret = -1;
+ goto end;
}
- test_case = &test_cases[test - 1];
+ test_case = &test_cases[test_case_id];
timeout = test_case->timeout;
if (!test_case->produces_validation_info) {
* All test cases need to provide, at minimum, the pid of the
* test application.
*/
- ret = fprintf(test_validation_output_file, "{ \"pid\": %i }", getpid());
+ ret = fprintf(test_validation_output_file, "{\"pid\": %i }", getpid());
if (ret < 0) {
PERROR("Failed to write application pid to test validation file");
goto end;
CURDIR=$(dirname "$0")/
TESTDIR=$CURDIR/../..
VALIDATE_SCRIPT="$CURDIR/validate_select_poll_epoll.py"
-NUM_TESTS=102
DISABLE_VALIDATE=0
# Babeltrace python bindings are required for the validation, but
LAST_OOPS=$(dmesg | grep " OOPS:" | cut -d' ' -f1 | tail -1)
LAST_BUG=$(dmesg | grep " BUG:" | cut -d' ' -f1 | tail -1)
+SUPPORTED_SYSCALLS_LIST=$("$CURDIR"/select_poll_epoll --list-supported-test-syscalls)
+SUPPORTED_SYSCALLS_COUNT=$(echo $SUPPORTED_SYSCALLS_LIST | awk -F '[\t,]' '{print NF}')
+
+# Two tests validate their trace for every supported syscall
+NUM_TESTS=$((88+(2*SUPPORTED_SYSCALLS_COUNT)))
+
# shellcheck source=../../utils/utils.sh
source $TESTDIR/utils/utils.sh
TRACE_PATH=$(mktemp -d -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_trace_path.XXXXXX")
TEST_VALIDATION_OUTPUT_PATH=$(mktemp -u -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_validation.XXXXXX")
- # arm64 does not have epoll_wait
- uname -m | grep -E "aarch64" >/dev/null 2>&1
- if test $? = 0; then
- SYSCALL_LIST="select,pselect6,poll,ppoll,epoll_ctl,epoll_pwait"
- else
- SYSCALL_LIST="select,pselect6,poll,ppoll,epoll_ctl,epoll_wait,epoll_pwait"
- fi
-
diag "Working cases for select, pselect6, poll, ppoll and epoll, waiting for input"
create_lttng_session_ok $SESSION_NAME "$TRACE_PATH"
- lttng_enable_kernel_syscall_ok $SESSION_NAME $SYSCALL_LIST
+ lttng_enable_kernel_syscall_ok $SESSION_NAME $SUPPORTED_SYSCALLS_LIST
add_context_kernel_ok $SESSION_NAME channel0 pid
start_lttng_tracing_ok
- yes | "$CURDIR"/select_poll_epoll --validation-file "$TEST_VALIDATION_OUTPUT_PATH" -t 1
+ yes | "$CURDIR"/select_poll_epoll --validation-file "$TEST_VALIDATION_OUTPUT_PATH" -t working_cases
stop_lttng_tracing_ok
- validate_trace "$SYSCALL_LIST" "$TRACE_PATH"
- check_trace_content -t 1 --validation-file "$TEST_VALIDATION_OUTPUT_PATH" "$TRACE_PATH"
+ validate_trace "$SUPPORTED_SYSCALLS_LIST" "$TRACE_PATH"
+ check_trace_content -t working_cases --validation-file "$TEST_VALIDATION_OUTPUT_PATH" "$TRACE_PATH"
destroy_lttng_session_ok $SESSION_NAME
TRACE_PATH=$(mktemp -d -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_trace_path.XXXXXX")
TEST_VALIDATION_OUTPUT_PATH=$(mktemp -u -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_validation.XXXXXX")
- # arm64 does not have epoll_wait
- uname -m | grep -E "aarch64" >/dev/null 2>&1
- if test $? = 0; then
- SYSCALL_LIST="select,pselect6,poll,ppoll,epoll_ctl,epoll_pwait"
- else
- SYSCALL_LIST="select,pselect6,poll,ppoll,epoll_ctl,epoll_wait,epoll_pwait"
- fi
-
diag "Timeout cases (1ms) for select, pselect6, poll, ppoll and epoll"
create_lttng_session_ok $SESSION_NAME "$TRACE_PATH"
- lttng_enable_kernel_syscall_ok $SESSION_NAME "$SYSCALL_LIST"
+ lttng_enable_kernel_syscall_ok $SESSION_NAME "$SUPPORTED_SYSCALLS_LIST"
add_context_kernel_ok $SESSION_NAME channel0 pid
start_lttng_tracing_ok
- yes | "$CURDIR"/select_poll_epoll --validation-file "$TEST_VALIDATION_OUTPUT_PATH" -t 2
+ yes | "$CURDIR"/select_poll_epoll --validation-file "$TEST_VALIDATION_OUTPUT_PATH" -t working_cases_timeout
stop_lttng_tracing_ok
- validate_trace "$SYSCALL_LIST" "$TRACE_PATH"
- check_trace_content -t 2 --validation-file "$TEST_VALIDATION_OUTPUT_PATH" "$TRACE_PATH" 2>/dev/null
+ validate_trace "$SUPPORTED_SYSCALLS_LIST" "$TRACE_PATH"
+ check_trace_content -t working_cases_timeout --validation-file "$TEST_VALIDATION_OUTPUT_PATH" "$TRACE_PATH" 2>/dev/null
destroy_lttng_session_ok $SESSION_NAME
function test_pselect_invalid_fd()
{
SESSION_NAME="syscall_payload"
- SYSCALL_LIST="pselect6"
+ local SYSCALL_LIST="pselect6"
TRACE_PATH=$(mktemp -d -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_trace_path.XXXXXX")
TEST_VALIDATION_OUTPUT_PATH=$(mktemp -u -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_validation.XXXXXX")
add_context_kernel_ok $SESSION_NAME channel0 pid
start_lttng_tracing_ok
- yes | "$CURDIR"/select_poll_epoll --validation-file "$TEST_VALIDATION_OUTPUT_PATH" -t 3
+ yes | "$CURDIR"/select_poll_epoll --validation-file "$TEST_VALIDATION_OUTPUT_PATH" -t pselect_invalid_fd
stop_lttng_tracing_ok
validate_trace "$SYSCALL_LIST" "$TRACE_PATH"
- check_trace_content -t 3 --validation-file "$TEST_VALIDATION_OUTPUT_PATH" "$TRACE_PATH" 2>/dev/null
+ check_trace_content -t pselect_invalid_fd --validation-file "$TEST_VALIDATION_OUTPUT_PATH" "$TRACE_PATH" 2>/dev/null
destroy_lttng_session_ok $SESSION_NAME
rm -f "$TEST_VALIDATION_OUTPUT_PATH"
}
-function test_big_ppoll()
+function test_ppoll_big()
{
SESSION_NAME="syscall_payload"
- SYSCALL_LIST="ppoll"
+ local SYSCALL_LIST="ppoll"
TRACE_PATH=$(mktemp -d -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_trace_path.XXXXXX")
TEST_VALIDATION_OUTPUT_PATH=$(mktemp -u -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_validation.XXXXXX")
add_context_kernel_ok $SESSION_NAME channel0 pid
start_lttng_tracing_ok
- yes | "$CURDIR"/select_poll_epoll --validation-file "$TEST_VALIDATION_OUTPUT_PATH" -t 4
+ yes | "$CURDIR"/select_poll_epoll --validation-file "$TEST_VALIDATION_OUTPUT_PATH" -t ppoll_big
stop_lttng_tracing_ok
validate_trace "$SYSCALL_LIST" "$TRACE_PATH"
- check_trace_content -t 4 --validation-file "$TEST_VALIDATION_OUTPUT_PATH" "$TRACE_PATH" 2>/dev/null
+ check_trace_content -t ppoll_big --validation-file "$TEST_VALIDATION_OUTPUT_PATH" "$TRACE_PATH" 2>/dev/null
destroy_lttng_session_ok $SESSION_NAME
rm -f "$TEST_VALIDATION_OUTPUT_PATH"
}
-function test_ppoll_overflow()
+function test_ppoll_fds_buffer_overflow()
{
SESSION_NAME="syscall_payload"
- SYSCALL_LIST="ppoll"
+ local SYSCALL_LIST="ppoll"
TRACE_PATH=$(mktemp -d -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_trace_path.XXXXXX")
TEST_VALIDATION_OUTPUT_PATH=$(mktemp -u -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_validation.XXXXXX")
start_lttng_tracing_ok
diag "Expect segfaults"
- yes | "$CURDIR"/select_poll_epoll --validation-file "$TEST_VALIDATION_OUTPUT_PATH" -t 5
+ yes | "$CURDIR"/select_poll_epoll --validation-file "$TEST_VALIDATION_OUTPUT_PATH" -t ppoll_fds_buffer_overflow
stop_lttng_tracing_ok
validate_trace "$SYSCALL_LIST" "$TRACE_PATH"
- check_trace_content -t 5 --validation-file "$TEST_VALIDATION_OUTPUT_PATH" "$TRACE_PATH" 2>/dev/null
+ check_trace_content -t ppoll_fds_buffer_overflow --validation-file "$TEST_VALIDATION_OUTPUT_PATH" "$TRACE_PATH" 2>/dev/null
destroy_lttng_session_ok $SESSION_NAME
rm -f "$TEST_VALIDATION_OUTPUT_PATH"
}
-function test_pselect_invalid_ptr()
+function test_pselect_invalid_pointer()
{
SESSION_NAME="syscall_payload"
- SYSCALL_LIST="pselect6"
+ local SYSCALL_LIST="pselect6"
TRACE_PATH=$(mktemp -d -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_trace_path.XXXXXX")
TEST_VALIDATION_OUTPUT_PATH=$(mktemp -u -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_validation.XXXXXX")
add_context_kernel_ok $SESSION_NAME channel0 pid
start_lttng_tracing_ok
- yes | "$CURDIR"/select_poll_epoll --validation-file "$TEST_VALIDATION_OUTPUT_PATH" -t 6
+ yes | "$CURDIR"/select_poll_epoll --validation-file "$TEST_VALIDATION_OUTPUT_PATH" -t pselect_invalid_pointer
stop_lttng_tracing_ok
validate_trace "$SYSCALL_LIST" "$TRACE_PATH"
- check_trace_content -t 6 --validation-file "$TEST_VALIDATION_OUTPUT_PATH" "$TRACE_PATH" 2>/dev/null
+ check_trace_content -t pselect_invalid_pointer --validation-file "$TEST_VALIDATION_OUTPUT_PATH" "$TRACE_PATH" 2>/dev/null
destroy_lttng_session_ok $SESSION_NAME
rm -f "$TEST_VALIDATION_OUTPUT_PATH"
}
-function test_ppoll_ulong_max()
+function test_ppoll_fds_ulong_max()
{
SESSION_NAME="syscall_payload"
- SYSCALL_LIST="ppoll"
+ local SYSCALL_LIST="ppoll"
TRACE_PATH=$(mktemp -d -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_trace_path.XXXXXX")
TEST_VALIDATION_OUTPUT_PATH=$(mktemp -u -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_validation.XXXXXX")
add_context_kernel_ok $SESSION_NAME channel0 pid
start_lttng_tracing_ok
- yes | "$CURDIR"/select_poll_epoll --validation-file "$TEST_VALIDATION_OUTPUT_PATH" -t 7
+ yes | "$CURDIR"/select_poll_epoll --validation-file "$TEST_VALIDATION_OUTPUT_PATH" -t ppoll_fds_ulong_max
stop_lttng_tracing_ok
validate_trace "$SYSCALL_LIST" "$TRACE_PATH"
- check_trace_content -t 7 --validation-file "$TEST_VALIDATION_OUTPUT_PATH" "$TRACE_PATH" 2>/dev/null
+ check_trace_content -t ppoll_fds_ulong_max --validation-file "$TEST_VALIDATION_OUTPUT_PATH" "$TRACE_PATH" 2>/dev/null
destroy_lttng_session_ok $SESSION_NAME
rm -f "$TEST_VALIDATION_OUTPUT_PATH"
}
-function test_epoll_pwait_invalid_ptr()
+function test_epoll_pwait_invalid_pointer()
{
SESSION_NAME="syscall_payload"
- SYSCALL_LIST="epoll_pwait"
+ local SYSCALL_LIST="epoll_pwait"
TRACE_PATH=$(mktemp -d -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_trace_path.XXXXXX")
TEST_VALIDATION_OUTPUT_PATH=$(mktemp -u -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_validation.XXXXXX")
add_context_kernel_ok $SESSION_NAME channel0 pid
start_lttng_tracing_ok
- yes | "$CURDIR"/select_poll_epoll --validation-file "$TEST_VALIDATION_OUTPUT_PATH" -t 8
+ yes | "$CURDIR"/select_poll_epoll --validation-file "$TEST_VALIDATION_OUTPUT_PATH" -t epoll_pwait_invalid_pointer
stop_lttng_tracing_ok
validate_trace "$SYSCALL_LIST" "$TRACE_PATH"
- check_trace_content -t 8 --validation-file "$TEST_VALIDATION_OUTPUT_PATH" "$TRACE_PATH" 2>/dev/null
+ check_trace_content -t epoll_pwait_invalid_pointer --validation-file "$TEST_VALIDATION_OUTPUT_PATH" "$TRACE_PATH" 2>/dev/null
destroy_lttng_session_ok $SESSION_NAME
rm -f "$TEST_VALIDATION_OUTPUT_PATH"
}
-function test_epoll_pwait_int_max()
+function test_epoll_pwait_fds_int_max()
{
SESSION_NAME="syscall_payload"
- SYSCALL_LIST="epoll_pwait"
+ local SYSCALL_LIST="epoll_pwait"
TRACE_PATH=$(mktemp -d -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_trace_path.XXXXXX")
TEST_VALIDATION_OUTPUT_PATH=$(mktemp -u -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_validation.XXXXXX")
add_context_kernel_ok $SESSION_NAME channel0 pid
start_lttng_tracing_ok
- yes | "$CURDIR"/select_poll_epoll --validation-file "$TEST_VALIDATION_OUTPUT_PATH" -t 9
+ yes | "$CURDIR"/select_poll_epoll --validation-file "$TEST_VALIDATION_OUTPUT_PATH" -t epoll_pwait_int_max
stop_lttng_tracing_ok
validate_trace "$SYSCALL_LIST" "$TRACE_PATH"
- check_trace_content -t 9 --validation-file "$TEST_VALIDATION_OUTPUT_PATH" "$TRACE_PATH" 2>/dev/null
+ check_trace_content -t epoll_pwait_int_max --validation-file "$TEST_VALIDATION_OUTPUT_PATH" "$TRACE_PATH" 2>/dev/null
destroy_lttng_session_ok $SESSION_NAME
rm -f "$TEST_VALIDATION_OUTPUT_PATH"
}
-function test_ppoll_concurrent()
+function test_ppoll_concurrent_write()
{
SESSION_NAME="syscall_payload"
- SYSCALL_LIST="ppoll"
+ local SYSCALL_LIST="ppoll"
TRACE_PATH=$(mktemp -d -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_trace_path.XXXXXX")
TEST_VALIDATION_OUTPUT_PATH=$(mktemp -u -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_validation.XXXXXX")
add_context_kernel_ok $SESSION_NAME channel0 pid
start_lttng_tracing_ok
- yes | "$CURDIR"/select_poll_epoll --validation-file "$TEST_VALIDATION_OUTPUT_PATH" -t 10
+ yes | "$CURDIR"/select_poll_epoll --validation-file "$TEST_VALIDATION_OUTPUT_PATH" -t ppoll_concurrent_write
stop_lttng_tracing_ok
validate_trace "$SYSCALL_LIST" "$TRACE_PATH"
- check_trace_content -t 10 --validation-file "$TEST_VALIDATION_OUTPUT_PATH" "$TRACE_PATH" 2>/dev/null
+ check_trace_content -t ppoll_concurrent_write --validation-file "$TEST_VALIDATION_OUTPUT_PATH" "$TRACE_PATH" 2>/dev/null
destroy_lttng_session_ok $SESSION_NAME
rm -f "$TEST_VALIDATION_OUTPUT_PATH"
}
-function test_epoll_pwait_concurrent()
+function test_epoll_pwait_concurrent_unmap()
{
SESSION_NAME="syscall_payload"
- SYSCALL_LIST="epoll_ctl,epoll_pwait"
+ local SYSCALL_LIST="epoll_ctl,epoll_pwait"
TRACE_PATH=$(mktemp -d -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_trace_path.XXXXXX")
TEST_VALIDATION_OUTPUT_PATH=$(mktemp -u -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_validation.XXXXXX")
start_lttng_tracing_ok
diag "Expect segfaults"
for i in $(seq 1 100); do
- yes | "$CURDIR"/select_poll_epoll --validation-file "$TEST_VALIDATION_OUTPUT_PATH" -t 11
+ yes | "$CURDIR"/select_poll_epoll --validation-file "$TEST_VALIDATION_OUTPUT_PATH" -t epoll_pwait_concurrent_munmap
done
stop_lttng_tracing_ok
# epoll_wait is not always generated in the trace (stress test)
validate_trace "epoll_ctl" "$TRACE_PATH"
- check_trace_content -t 11 --validation-file "$TEST_VALIDATION_OUTPUT_PATH" "$TRACE_PATH" 2>/dev/null
+ check_trace_content -t epoll_pwait_concurrent_munmap --validation-file "$TEST_VALIDATION_OUTPUT_PATH" "$TRACE_PATH" 2>/dev/null
destroy_lttng_session_ok $SESSION_NAME
isroot=0
fi
+diag "Supported syscalls are $SUPPORTED_SYSCALLS_LIST"
+
skip $isroot "Root access is needed. Skipping all tests." $NUM_TESTS ||
{
validate_lttng_modules_present
test_working_cases
test_timeout_cases
test_pselect_invalid_fd
- test_big_ppoll
- test_ppoll_overflow
- test_pselect_invalid_ptr
- test_ppoll_ulong_max
- test_epoll_pwait_invalid_ptr
- test_epoll_pwait_int_max
- test_ppoll_concurrent
- test_epoll_pwait_concurrent
+ test_ppoll_big
+ test_ppoll_fds_buffer_overflow
+ test_pselect_invalid_pointer
+ test_ppoll_fds_ulong_max
+ test_epoll_pwait_invalid_pointer
+ test_epoll_pwait_fds_int_max
+ test_ppoll_concurrent_write
+ test_epoll_pwait_concurrent_unmap
stop_lttng_sessiond
pass
-class Test1(TraceParser):
+class WorkingCases(TraceParser):
def __init__(self, trace, validation_args):
super().__init__(trace, validation_args['pid'])
# Save values of local variables to print in case of test failure
self.recorded_values["epoll_pwait_exit"] = locals()
-class Test2(TraceParser):
+class WorkingCasesTimeout(TraceParser):
def __init__(self, trace, validation_args):
super().__init__(trace, validation_args['pid'])
self.expect["select_entry"]["select_timeout_in_fd0"] = 0
self.recorded_values["epoll_wait_exit"] = locals()
-class Test3(TraceParser):
+class PselectInvalidFd(TraceParser):
def __init__(self, trace, validation_args):
super().__init__(trace, validation_args['pid'])
self.expect["select_entry"]["select_invalid_fd_in"] = 0
self.recorded_values["select_exit"] = locals()
-class Test4(TraceParser):
+class PpollBig(TraceParser):
def __init__(self, trace, validation_args):
super().__init__(trace, validation_args['pid'])
self.expect["poll_entry"]["big_poll_in"] = 0
# Save values of local variables to print in case of test failure
self.recorded_values["poll_exit"] = locals()
-class Test5(TraceParser):
+class PpollFdsBufferOverflow(TraceParser):
def __init__(self, trace, validation_args):
super().__init__(trace, validation_args['pid'])
self.expect["poll_entry"]["poll_overflow_in"] = 0
self.recorded_values["poll_exit"] = locals()
-class Test6(TraceParser):
+class PselectInvalidPointer(TraceParser):
def __init__(self, trace, validation_args):
super().__init__(trace, validation_args['pid'])
self.expect["select_entry"]["pselect_invalid_in"] = 0
self.recorded_values["select_exit"] = locals()
-class Test7(TraceParser):
+class PpollFdsULongMax(TraceParser):
def __init__(self, trace, validation_args):
super().__init__(trace, validation_args['pid'])
self.expect["poll_entry"]["poll_max_in"] = 0
self.recorded_values["poll_exit"] = locals()
-class Test8(TraceParser):
+class EpollPwaitInvalidPointer(TraceParser):
def __init__(self, trace, validation_args):
super().__init__(trace, validation_args['pid'])
self.recorded_values["epoll_wait_exit"] = locals()
-class Test9(TraceParser):
+class EpollPwaitIntMax(TraceParser):
def __init__(self, trace, validation_args):
super().__init__(trace, validation_args['pid'])
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Trace parser')
parser.add_argument('path', metavar="<path/to/trace>", help='Trace path')
- parser.add_argument('-t', '--test', type=int, help='Test to validate')
+ parser.add_argument('-t', '--test', type=str, help='Test to validate')
parser.add_argument('-o', '--validation-file', type=str, help='Validation file path')
args = parser.parse_args()
t = None
- if args.test == 1:
- t = Test1(traces, test_validation_args)
- elif args.test == 2:
- t = Test2(traces, test_validation_args)
- elif args.test == 3:
- t = Test3(traces, test_validation_args)
- elif args.test == 4:
- t = Test4(traces, test_validation_args)
- elif args.test == 5:
- t = Test5(traces, test_validation_args)
- elif args.test == 6:
- t = Test6(traces, test_validation_args)
- elif args.test == 7:
- t = Test7(traces, test_validation_args)
- elif args.test == 8:
- t = Test8(traces, test_validation_args)
- elif args.test == 9:
- t = Test9(traces, test_validation_args)
- elif args.test == 10:
+ if args.test == "working_cases":
+ t = WorkingCases(traces, test_validation_args)
+ elif args.test == "working_cases_timeout":
+ t = WorkingCasesTimeout(traces, test_validation_args)
+ elif args.test == "pselect_invalid_fd":
+ t = PselectInvalidFd(traces, test_validation_args)
+ elif args.test == "ppoll_big":
+ t = PpollBig(traces, test_validation_args)
+ elif args.test == "ppoll_fds_buffer_overflow":
+ t = PpollFdsBufferOverflow(traces, test_validation_args)
+ elif args.test == "pselect_invalid_pointer":
+ t = PselectInvalidPointer(traces, test_validation_args)
+ elif args.test == "ppoll_fds_ulong_max":
+ t = PpollFdsULongMax(traces, test_validation_args)
+ elif args.test == "epoll_pwait_invalid_pointer":
+ t = EpollPwaitInvalidPointer(traces, test_validation_args)
+ elif args.test == "epoll_pwait_int_max":
+ t = EpollPwaitIntMax(traces, test_validation_args)
+ elif args.test == "ppoll_concurrent_write":
# stress test, nothing reliable to check
ret = 0
- elif args.test == 11:
+ elif args.test == "epoll_pwait_concurrent_munmap":
# stress test, nothing reliable to check
ret = 0
else: