summaryrefslogtreecommitdiffstats
path: root/tools/guest-diag/sysc_shim.c
blob: 9b07e4c53498b5a895efe9b0b9ed97f7c1cb3e32 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
/* sysc_shim.c - intercept syscall() so we can dump ioctl buffer *results*
 * for UVM ioctls (libcuda calls syscall(SYS_ioctl, ...) directly, so an
 * ioctl() wrapper is bypassed but syscall() is not).
 * Build in guest: gcc -shared -fPIC -O1 -o /tmp/sysc.so sysc_shim.c -ldl
 * Run: LD_PRELOAD=/tmp/sysc.so /tmp/cdt
 */
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdarg.h>
#include <stddef.h>
#include <sys/syscall.h>
#include <unistd.h>

static long (*real_syscall)(long, ...);

static void dump(const char *tag, unsigned long req, void *arg, long ret)
{
	unsigned int *p = (unsigned int *)arg;
	char buf[512];
	int n, i;
	long *vp = (long *)arg;

	if (!p)
		return;
	n = 0;
	n += __builtin_snprintf(buf + n, sizeof(buf) - n,
				"SYSC[%s] req=0x%lx ret=%ld dwords: ", tag, req,
				ret);
	for (i = 0; i < 16 && n < (int)sizeof(buf) - 16; i++)
		n += __builtin_snprintf(buf + n, sizeof(buf) - n, "%08x ",
					p[i]);
	(void)vp;
	write(2, buf, n);
	write(2, "\n", 1);
}

long syscall(long nr, ...)
{
	va_list ap;
	long a1, a2, a3, a4, a5, a6;
	long ret;

	if (!real_syscall)
		real_syscall = dlsym(RTLD_NEXT, "syscall");

	va_start(ap, nr);
	a1 = va_arg(ap, long);
	a2 = va_arg(ap, long);
	a3 = va_arg(ap, long);
	a4 = va_arg(ap, long);
	a5 = va_arg(ap, long);
	a6 = va_arg(ap, long);
	va_end(ap);

	ret = real_syscall(nr, a1, a2, a3, a4, a5, a6);

	if (nr == SYS_ioctl) {
		unsigned long req = (unsigned long)a2;
		switch (req) {
		case 0x1:  /* UVM_RESERVE_VA */
		case 0x2:  /* UVM_RELEASE_VA */
		case 0x25: /* UVM_REGISTER_GPU */
		case 0x27: /* UVM_PAGEABLE_MEM_ACCESS */
		case 0x17: /* UVM_EVENT_CTRL */
		case 0x19: /* UVM_REGISTER_MPS_CLIENT */
			dump("uvmioctl", req, (void *)a3, ret);
			break;
		default:
			break;
		}
	}
	return ret;
}