1 #include <linux/init.h> 2 #include <linux/seq_file.h> 3 #include <linux/fs.h> 4 #include <linux/mm.h> 5 #include <linux/proc_fs.h> 6 #include <linux/slab.h> 7 #include <xen/interface/platform.h> 8 #include <asm/xen/hypercall.h> 9 #include <xen/xen-ops.h> 10 #include "xenfs.h" 11 12 13 #define XEN_KSYM_NAME_LEN 127 /* Hypervisor may have different name length */ 14 15 struct xensyms { 16 struct xen_platform_op op; 17 char *name; 18 uint32_t namelen; 19 }; 20 21 /* Grab next output page from the hypervisor */ 22 static int xensyms_next_sym(struct xensyms *xs) 23 { 24 int ret; 25 struct xenpf_symdata *symdata = &xs->op.u.symdata; 26 uint64_t symnum; 27 28 memset(xs->name, 0, xs->namelen); 29 symdata->namelen = xs->namelen; 30 31 symnum = symdata->symnum; 32 33 ret = HYPERVISOR_platform_op(&xs->op); 34 if (ret < 0) 35 return ret; 36 37 /* 38 * If hypervisor's symbol didn't fit into the buffer then allocate 39 * a larger buffer and try again. 40 */ 41 if (unlikely(symdata->namelen > xs->namelen)) { 42 kfree(xs->name); 43 44 xs->namelen = symdata->namelen; 45 xs->name = kzalloc(xs->namelen, GFP_KERNEL); 46 if (!xs->name) 47 return -ENOMEM; 48 49 set_xen_guest_handle(symdata->name, xs->name); 50 symdata->symnum--; /* Rewind */ 51 52 ret = HYPERVISOR_platform_op(&xs->op); 53 if (ret < 0) 54 return ret; 55 } 56 57 if (symdata->symnum == symnum) 58 /* End of symbols */ 59 return 1; 60 61 return 0; 62 } 63 64 static void *xensyms_start(struct seq_file *m, loff_t *pos) 65 { 66 struct xensyms *xs = (struct xensyms *)m->private; 67 68 xs->op.u.symdata.symnum = *pos; 69 70 if (xensyms_next_sym(xs)) 71 return NULL; 72 73 return m->private; 74 } 75 76 static void *xensyms_next(struct seq_file *m, void *p, loff_t *pos) 77 { 78 struct xensyms *xs = (struct xensyms *)m->private; 79 80 xs->op.u.symdata.symnum = ++(*pos); 81 82 if (xensyms_next_sym(xs)) 83 return NULL; 84 85 return p; 86 } 87 88 static int xensyms_show(struct seq_file *m, void *p) 89 { 90 struct xensyms *xs = (struct xensyms *)m->private; 91 struct xenpf_symdata *symdata = &xs->op.u.symdata; 92 93 seq_printf(m, "%016llx %c %s\n", symdata->address, 94 symdata->type, xs->name); 95 96 return 0; 97 } 98 99 static void xensyms_stop(struct seq_file *m, void *p) 100 { 101 } 102 103 static const struct seq_operations xensyms_seq_ops = { 104 .start = xensyms_start, 105 .next = xensyms_next, 106 .show = xensyms_show, 107 .stop = xensyms_stop, 108 }; 109 110 static int xensyms_open(struct inode *inode, struct file *file) 111 { 112 struct seq_file *m; 113 struct xensyms *xs; 114 int ret; 115 116 ret = seq_open_private(file, &xensyms_seq_ops, 117 sizeof(struct xensyms)); 118 if (ret) 119 return ret; 120 121 m = file->private_data; 122 xs = (struct xensyms *)m->private; 123 124 xs->namelen = XEN_KSYM_NAME_LEN + 1; 125 xs->name = kzalloc(xs->namelen, GFP_KERNEL); 126 if (!xs->name) { 127 seq_release_private(inode, file); 128 return -ENOMEM; 129 } 130 set_xen_guest_handle(xs->op.u.symdata.name, xs->name); 131 xs->op.cmd = XENPF_get_symbol; 132 xs->op.u.symdata.namelen = xs->namelen; 133 134 return 0; 135 } 136 137 static int xensyms_release(struct inode *inode, struct file *file) 138 { 139 struct seq_file *m = file->private_data; 140 struct xensyms *xs = (struct xensyms *)m->private; 141 142 kfree(xs->name); 143 return seq_release_private(inode, file); 144 } 145 146 const struct file_operations xensyms_ops = { 147 .open = xensyms_open, 148 .read = seq_read, 149 .llseek = seq_lseek, 150 .release = xensyms_release 151 }; 152