/* 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 #include #include #include #include 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; }