vmm: Attempt to backtrace the guest on error
[akaros.git] / user / vmm / util.c
1 /* Copyright (c) 2017 Google Inc.
2  * See LICENSE for details.
3  *
4  * Utility functions. */
5
6 #include <stdio.h>
7 #include <string.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <errno.h>
11 #include <sys/fcntl.h>
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <vmm/util.h>
15 #include <vmm/vmm.h>
16
17 ssize_t cat(char *filename, void *where, size_t memsize)
18 {
19         int fd;
20         ssize_t amt, tot = 0;
21         struct stat buf;
22
23         fd = open(filename, O_RDONLY);
24         if (fd < 0) {
25                 fprintf(stderr, "Can't open %s: %r\n", filename);
26                 return -1;
27         }
28
29         if (fstat(fd, &buf) < 0) {
30                 fprintf(stderr, "Can't stat %s: %r\n", filename);
31                 close(fd);
32                 return -1;
33         }
34
35         if (buf.st_size > memsize) {
36                 fprintf(stderr,
37                         "file is %d bytes, but we only have %d bytes to place it\n",
38                         buf.st_size, memsize);
39                 errno = ENOMEM;
40                 close(fd);
41                 return -1;
42         }
43
44         while (tot < buf.st_size) {
45                 amt = read(fd, where, buf.st_size - tot);
46                 if (amt < 0) {
47                         tot = -1;
48                         break;
49                 }
50                 if (amt == 0)
51                         break;
52                 where += amt;
53                 tot += amt;
54         }
55
56         close(fd);
57         return tot;
58 }
59
60 void backtrace_guest_thread(FILE *f, struct guest_thread *vm_thread)
61 {
62         struct vm_trapframe *vm_tf = gth_to_vmtf(vm_thread);
63         uintptr_t guest_pc, guest_fp, host_fp;
64         uintptr_t frame[2];
65
66         guest_pc = vm_tf->tf_rip;
67         guest_fp = vm_tf->tf_rbp;
68
69         /* The BT should work for any code using frame pointers.  Most of the time,
70          * this will be vmlinux, and calling it that helps our backtrace.  This
71          * spits out the format that is parsed by bt-akaros.sh. */
72         fprintf(f, "Backtracing guest, vmlinux is assumed, but check addrs\n");
73         for (int i = 1; i < 30; i++) {
74                 fprintf(f, "#%02d Addr %p is in vmlinux at offset %p\n", i, guest_pc,
75                         guest_pc);
76                 if (!guest_fp)
77                         break;
78                 if (gvatogpa(vm_thread, guest_fp, &host_fp))
79                         break;
80                 memcpy(frame, (void*)host_fp, 2 * sizeof(uintptr_t));
81                 guest_pc = frame[1];
82                 guest_fp = frame[0];
83         }
84 }