tools/testing/selftests/x86/unwind_vdso.c

Source file repositories/reference/linux-study-clean/tools/testing/selftests/x86/unwind_vdso.c

File Facts

System
Linux kernel
Corpus path
tools/testing/selftests/x86/unwind_vdso.c
Extension
.c
Size
4058 bytes
Lines
172
Domain
Support Tooling And Documentation
Bucket
tools
Inferred role
Support Tooling And Documentation: implementation source
Status
source 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

struct unwind_state {
	unsigned long ip;	/* trap source */
	int depth;		/* -1 until we hit the trap source */
};

_Unwind_Reason_Code trace_fn(struct _Unwind_Context * ctx, void *opaque)
{
	struct unwind_state *state = opaque;
	unsigned long ip = _Unwind_GetIP(ctx);

	if (state->depth == -1) {
		if (ip == state->ip)
			state->depth = 0;
		else
			return _URC_NO_REASON;	/* Not there yet */
	}
	printf("\t  0x%lx\n", ip);

	if (ip == return_address) {
		/* Here we are. */
		unsigned long eax = _Unwind_GetGR(ctx, 0);
		unsigned long ecx = _Unwind_GetGR(ctx, 1);
		unsigned long edx = _Unwind_GetGR(ctx, 2);
		unsigned long ebx = _Unwind_GetGR(ctx, 3);
		unsigned long ebp = _Unwind_GetGR(ctx, 5);
		unsigned long esi = _Unwind_GetGR(ctx, 6);
		unsigned long edi = _Unwind_GetGR(ctx, 7);
		bool ok = (eax == SYS_getpid || eax == getpid()) &&
			ebx == 1 && ecx == 2 && edx == 3 &&
			esi == 4 && edi == 5 && ebp == 6;

		if (!ok)
			nerrs++;
		printf("[%s]\t  NR = %ld, args = %ld, %ld, %ld, %ld, %ld, %ld\n",
		       (ok ? "OK" : "FAIL"),
		       eax, ebx, ecx, edx, esi, edi, ebp);

		return _URC_NORMAL_STOP;
	} else {
		state->depth++;
		return _URC_NO_REASON;
	}
}

static void sigtrap(int sig, siginfo_t *info, void *ctx_void)
{
	ucontext_t *ctx = (ucontext_t *)ctx_void;
	struct unwind_state state;
	unsigned long ip = ctx->uc_mcontext.gregs[REG_EIP];

	if (!got_sysinfo && ip == sysinfo) {
		got_sysinfo = true;

		/* Find the return address. */
		return_address = *(unsigned long *)(unsigned long)ctx->uc_mcontext.gregs[REG_ESP];

		printf("\tIn vsyscall at 0x%lx, returning to 0x%lx\n",
		       ip, return_address);
	}

	if (!got_sysinfo)
		return;		/* Not there yet */

	if (ip == return_address) {
		ctx->uc_mcontext.gregs[REG_EFL] &= ~X86_EFLAGS_TF;
		printf("\tVsyscall is done\n");
		return;
	}

	printf("\tSIGTRAP at 0x%lx\n", ip);

	state.ip = ip;
	state.depth = -1;
	_Unwind_Backtrace(trace_fn, &state);
}

int main()
{
	sysinfo = getauxval(AT_SYSINFO);
	printf("\tAT_SYSINFO is 0x%lx\n", sysinfo);

	Dl_info info;
	if (!dladdr((void *)sysinfo, &info)) {
		printf("[WARN]\tdladdr failed on AT_SYSINFO\n");
	} else {
		printf("[OK]\tAT_SYSINFO maps to %s, loaded at 0x%p\n",
		       info.dli_fname, info.dli_fbase);
	}

	sethandler(SIGTRAP, sigtrap, 0);

Annotation

Implementation Notes