tools/testing/selftests/ptrace/get_syscall_info.c

Source file repositories/reference/linux-study-clean/tools/testing/selftests/ptrace/get_syscall_info.c

File Facts

System
Linux kernel
Corpus path
tools/testing/selftests/ptrace/get_syscall_info.c
Extension
.c
Size
6552 bytes
Lines
272
Domain
Support Tooling And Documentation
Bucket
tools
Inferred role
Support Tooling And Documentation: syscall or user/kernel boundary
Status
core implementation candidate

Why This File Exists

Repository support layer: documentation, build tooling, samples, user-space helper tools, generated initramfs support, licenses, and validation utilities.

Dependency Surface

Detected Declarations

Annotated Snippet

ASSERT_EQ(0, sys_ptrace(PTRACE_TRACEME, 0, 0, 0)) {
			TH_LOG("PTRACE_TRACEME: %m");
		}
		ASSERT_EQ(0, kill(pid, SIGSTOP)) {
			/* cannot happen */
			TH_LOG("kill SIGSTOP: %m");
		}
		for (unsigned int i = 0; i < ARRAY_SIZE(args); ++i) {
			syscall(args[i][0],
				args[i][1], args[i][2], args[i][3],
				args[i][4], args[i][5], args[i][6]);
		}
		/* unreachable */
		_exit(1);
	}

	const struct {
		unsigned int is_error;
		int rval;
	} *exp_param, exit_param[] = {
		{ 1, -ENOENT },	/* chdir */
		{ 0, pid }	/* gettid */
	};

	unsigned int ptrace_stop;

	for (ptrace_stop = 0; ; ++ptrace_stop) {
		struct ptrace_syscall_info info = {
			.op = 0xff	/* invalid PTRACE_SYSCALL_INFO_* op */
		};
		const size_t size = sizeof(info);
		const int expected_none_size =
			(void *) &info.entry - (void *) &info;
		const int expected_entry_size =
			(void *) &info.entry.args[6] - (void *) &info;
		const int expected_exit_size =
			(void *) (&info.exit.is_error + 1) -
			(void *) &info;
		int status;
		long rc;

		ASSERT_EQ(pid, wait(&status)) {
			/* cannot happen */
			LOG_KILL_TRACEE("wait: %m");
		}
		if (WIFEXITED(status)) {
			pid = 0;	/* the tracee is no more */
			ASSERT_EQ(0, WEXITSTATUS(status));
			break;
		}
		ASSERT_FALSE(WIFSIGNALED(status)) {
			pid = 0;	/* the tracee is no more */
			LOG_KILL_TRACEE("unexpected signal %u",
					WTERMSIG(status));
		}
		ASSERT_TRUE(WIFSTOPPED(status)) {
			/* cannot happen */
			LOG_KILL_TRACEE("unexpected wait status %#x", status);
		}

		switch (WSTOPSIG(status)) {
		case SIGSTOP:
			ASSERT_EQ(0, ptrace_stop) {
				LOG_KILL_TRACEE("unexpected signal stop");
			}
			ASSERT_EQ(0, sys_ptrace(PTRACE_SETOPTIONS, pid, 0,
						PTRACE_O_TRACESYSGOOD)) {
				LOG_KILL_TRACEE("PTRACE_SETOPTIONS: %m");
			}
			ASSERT_LT(0, (rc = sys_ptrace(PTRACE_GET_SYSCALL_INFO,
						      pid, size,
						      (unsigned long) &info))) {
				LOG_KILL_TRACEE("PTRACE_GET_SYSCALL_INFO: %m");
			}
			ASSERT_EQ(expected_none_size, rc) {
				LOG_KILL_TRACEE("signal stop mismatch");
			}
			ASSERT_EQ(PTRACE_SYSCALL_INFO_NONE, info.op) {
				LOG_KILL_TRACEE("signal stop mismatch");
			}
			ASSERT_TRUE(info.arch) {
				LOG_KILL_TRACEE("signal stop mismatch");
			}
			ASSERT_TRUE(info.instruction_pointer) {
				LOG_KILL_TRACEE("signal stop mismatch");
			}
			ASSERT_TRUE(info.stack_pointer) {
				LOG_KILL_TRACEE("signal stop mismatch");
			}
			break;

Annotation

Implementation Notes