summaryrefslogtreecommitdiffstats
path: root/tools/guest-diag/ptrace_ioctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/guest-diag/ptrace_ioctl.c')
-rw-r--r--tools/guest-diag/ptrace_ioctl.c236
1 files changed, 236 insertions, 0 deletions
diff --git a/tools/guest-diag/ptrace_ioctl.c b/tools/guest-diag/ptrace_ioctl.c
new file mode 100644
index 0000000..5f96b31
--- /dev/null
+++ b/tools/guest-diag/ptrace_ioctl.c
@@ -0,0 +1,236 @@
+/* ptrace_ioctl.c - follow a child with PTRACE_SYSCALL and dump the buffer
+ * results of selected UVM ioctls. Needed because libcuda issues raw syscall
+ * instructions (LD_PRELOAD/ltrace never see these).
+ *
+ * Build (guest): gcc -O1 -w -o /tmp/ptio ptrace_ioctl.c
+ * Run: /tmp/ptio /tmp/cdt
+ */
+#define _GNU_SOURCE
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#define SYS_IOCTL_X86_64 16
+
+struct syscall_info {
+ unsigned char op;
+ unsigned char pad[3];
+ unsigned int arch;
+ unsigned long long instruction_pointer;
+ unsigned long long stack_pointer;
+ union {
+ struct {
+ unsigned long long nr;
+ unsigned long long args[6];
+ } entry;
+ struct {
+ long long rval;
+ unsigned char is_error;
+ } exit;
+ } u;
+};
+
+static int interesting(unsigned long req)
+{
+ 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 */
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static void dump_words(pid_t pid, unsigned long addr, int nwords)
+{
+ int i;
+
+ fprintf(stderr, " buffer @%#lx:", addr);
+ for (i = 0; i < nwords; i++) {
+ errno = 0;
+ long v = ptrace(PTRACE_PEEKDATA, pid, addr + i * 8, NULL);
+ if (errno)
+ break;
+ fprintf(stderr, " %016lx", (unsigned long)v);
+ }
+ fprintf(stderr, "\n");
+}
+
+struct saved {
+ pid_t pid;
+ int used;
+ unsigned long req, arg;
+} saved[64];
+
+static struct saved *slot(pid_t pid)
+{
+ int i, free_i = -1;
+
+ for (i = 0; i < 64; i++) {
+ if (saved[i].used && saved[i].pid == pid)
+ return &saved[i];
+ if (!saved[i].used && free_i < 0)
+ free_i = i;
+ }
+ if (free_i >= 0) {
+ saved[free_i].used = 1;
+ saved[free_i].pid = pid;
+ saved[free_i].req = 0;
+ return &saved[free_i];
+ }
+ return NULL;
+}
+
+int main(int argc, char **argv)
+{
+ pid_t pid;
+ int nprint = 0;
+
+ if (argc < 2) {
+ fprintf(stderr, "usage: %s prog [args...]\n", argv[0]);
+ return 2;
+ }
+
+ pid = fork();
+ if (pid == 0) {
+ ptrace(PTRACE_TRACEME, 0, 0, 0);
+ raise(SIGSTOP);
+ execvp(argv[1], &argv[1]);
+ perror("execvp");
+ _exit(127);
+ }
+
+ waitpid(pid, NULL, WUNTRACED);
+ ptrace(PTRACE_SETOPTIONS, pid, 0,
+ (void *)(PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACECLONE |
+ PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_EXITKILL));
+ ptrace(PTRACE_SYSCALL, pid, 0, 0);
+
+ fprintf(stderr, "[ptio] attached to pid %d\n", pid);
+ for (;;) {
+ int status;
+ pid_t p = waitpid(-1, &status, __WALL);
+
+ if (p < 0) {
+ if (errno == EINTR)
+ continue;
+ break;
+ }
+ if (WIFEXITED(status) || WIFSIGNALED(status))
+ continue;
+ if (!WIFSTOPPED(status))
+ continue;
+
+ {
+ int sig = WSTOPSIG(status);
+ struct syscall_info si;
+
+ memset(&si, 0, sizeof(si));
+ if ((sig == (SIGTRAP | 0x80)) &&
+ ptrace(PTRACE_GET_SYSCALL_INFO, p, sizeof(si), &si) > 0) {
+ struct saved *sv = slot(p);
+
+ if (si.op == 1 /* entry */) {
+ if (sv && si.u.entry.nr == SYS_IOCTL_X86_64) {
+ sv->req = si.u.entry.args[1];
+ sv->arg = si.u.entry.args[2];
+ if (sv->req == 0x25) {
+ fprintf(stderr, "[ptio] ENTER UVM_REGISTER_GPU pid=%d\n", p);
+ dump_words(p, sv->arg, 6);
+ fprintf(stderr, " ^ IN: uuid(2q) | numaEnabled numaNodeId | rmCtrlFd hClient | hSmcPartRef rmStatus\n");
+ }
+ } else if (sv) {
+ sv->req = 0;
+ }
+ } else if (si.op == 2 /* exit */ && sv &&
+ ((sv->req & 0xff) == 0x4629ul ||
+ ((sv->req & 0xffff00fful) == 0x0046002bul) ||
+ ((sv->req & 0xffff00fful) == 0x0046002aul))) {
+ unsigned int own = (unsigned int)(sv->req & 0xff);
+ long q0 = 0, q1 = 0, q2 = 0, q3 = 0;
+ unsigned long st = 0;
+
+ errno = 0; q0 = ptrace(PTRACE_PEEKDATA, p, sv->arg, NULL);
+ errno = 0; q1 = ptrace(PTRACE_PEEKDATA, p, sv->arg + 8, NULL);
+ errno = 0; q2 = ptrace(PTRACE_PEEKDATA, p, sv->arg + 16, NULL);
+ errno = 0; q3 = ptrace(PTRACE_PEEKDATA, p, sv->arg + 24, NULL);
+ if (own == 0x29)
+ st = (unsigned long)((q1 >> 32) & 0xfffffffful);
+ else
+ st = (unsigned long)((q3 >> 32) & 0xfffffffful);
+ if (st != 0)
+ fprintf(stderr,
+ "[rmio] pid=%d nr=0x%x status=0x%lx hClient=0x%lx hObj=0x%lx cmd/class=0x%lx size=%lu\n",
+ p, own,
+ st,
+ (unsigned long)(q0 & 0xfffffffful),
+ (unsigned long)((q0 >> 32) & 0xfffffffful),
+ (unsigned long)(q1 & 0xfffffffful),
+ (unsigned long)((q3 >> 32) & 0xfffffffful));
+ } else if (si.op == 2 /* exit */ && sv &&
+ sv->req == 0xc020462aul) {
+ long q0, q1, q2, q3;
+ errno = 0;
+ q1 = ptrace(PTRACE_PEEKDATA, p, sv->arg + 8, NULL);
+ errno = 0;
+ q2 = ptrace(PTRACE_PEEKDATA, p, sv->arg + 16, NULL);
+ errno = 0;
+ q3 = ptrace(PTRACE_PEEKDATA, p, sv->arg + 24, NULL);
+ q0 = ptrace(PTRACE_PEEKDATA, p, sv->arg, NULL);
+ (void)q0;
+ fprintf(stderr,
+ "[rmctl] pid=%d cmd=0x%lx hClient=0x%lx params=%#lx size=%lu status=0x%lx\n",
+ p, (unsigned long)(q1 & 0xfffffffful),
+ (unsigned long)(q0 & 0xfffffffful),
+ (unsigned long)(q2 & 0xfffffffffffful),
+ (unsigned long)((q2 >> 32) & 0xfffffffful),
+ (unsigned long)((q3 >> 32) & 0xfffffffful));
+ if (((q3 >> 32) & 0xfffffffful) != 0 &&
+ (q2 & 0xfffffffffffful) > 0x10000) {
+ fprintf(stderr, " params:");
+ {
+ int i2;
+ for (i2 = 0; i2 < 6; i2++) {
+ errno = 0;
+ long v = ptrace(PTRACE_PEEKDATA, p,
+ (unsigned long)(q2 & 0xfffffffffffful) + i2 * 8, NULL);
+ if (errno)
+ break;
+ fprintf(stderr, " %016lx",
+ (unsigned long)v);
+ }
+ }
+ fprintf(stderr, "\n");
+ }
+ } else if (si.op == 2 /* exit */ && sv &&
+ interesting(sv->req)) {
+ fprintf(stderr,
+ "[ptio] pid=%d ioctl req=0x%lx arg=%#lx ret=%ld%s\n",
+ p, sv->req, sv->arg,
+ si.u.exit.rval,
+ interesting(sv->req) ? " *" : "");
+ if (sv->req == 0x25) {
+ dump_words(p, sv->arg, 6);
+ fprintf(stderr,
+ " ^ UVM_REGISTER_GPU: uuid(2q) | numaEnabled numaNodeId rmCtrlFd hClient | hSmcPartRef rmStatus\n");
+ } else {
+ dump_words(p, sv->arg, 4);
+ }
+ }
+ }
+ ptrace(PTRACE_SYSCALL, p, 0, sig == (SIGTRAP | 0x80) ? 0 :
+ (sig == SIGTRAP ? 0 : sig));
+ }
+ }
+ return 0;
+}