0001
0002 #include <linux/init.h>
0003 #include <linux/seq_file.h>
0004 #include <linux/fs.h>
0005 #include <linux/mm.h>
0006 #include <linux/proc_fs.h>
0007 #include <linux/slab.h>
0008 #include <xen/interface/platform.h>
0009 #include <asm/xen/hypercall.h>
0010 #include <xen/xen-ops.h>
0011 #include "xenfs.h"
0012
0013
0014 #define XEN_KSYM_NAME_LEN 127
0015
0016 struct xensyms {
0017 struct xen_platform_op op;
0018 char *name;
0019 uint32_t namelen;
0020 };
0021
0022
0023 static int xensyms_next_sym(struct xensyms *xs)
0024 {
0025 int ret;
0026 struct xenpf_symdata *symdata = &xs->op.u.symdata;
0027 uint64_t symnum;
0028
0029 memset(xs->name, 0, xs->namelen);
0030 symdata->namelen = xs->namelen;
0031
0032 symnum = symdata->symnum;
0033
0034 ret = HYPERVISOR_platform_op(&xs->op);
0035 if (ret < 0)
0036 return ret;
0037
0038
0039
0040
0041
0042 if (unlikely(symdata->namelen > xs->namelen)) {
0043 kfree(xs->name);
0044
0045 xs->namelen = symdata->namelen;
0046 xs->name = kzalloc(xs->namelen, GFP_KERNEL);
0047 if (!xs->name)
0048 return -ENOMEM;
0049
0050 set_xen_guest_handle(symdata->name, xs->name);
0051 symdata->symnum--;
0052
0053 ret = HYPERVISOR_platform_op(&xs->op);
0054 if (ret < 0)
0055 return ret;
0056 }
0057
0058 if (symdata->symnum == symnum)
0059
0060 return 1;
0061
0062 return 0;
0063 }
0064
0065 static void *xensyms_start(struct seq_file *m, loff_t *pos)
0066 {
0067 struct xensyms *xs = (struct xensyms *)m->private;
0068
0069 xs->op.u.symdata.symnum = *pos;
0070
0071 if (xensyms_next_sym(xs))
0072 return NULL;
0073
0074 return m->private;
0075 }
0076
0077 static void *xensyms_next(struct seq_file *m, void *p, loff_t *pos)
0078 {
0079 struct xensyms *xs = (struct xensyms *)m->private;
0080
0081 xs->op.u.symdata.symnum = ++(*pos);
0082
0083 if (xensyms_next_sym(xs))
0084 return NULL;
0085
0086 return p;
0087 }
0088
0089 static int xensyms_show(struct seq_file *m, void *p)
0090 {
0091 struct xensyms *xs = (struct xensyms *)m->private;
0092 struct xenpf_symdata *symdata = &xs->op.u.symdata;
0093
0094 seq_printf(m, "%016llx %c %s\n", symdata->address,
0095 symdata->type, xs->name);
0096
0097 return 0;
0098 }
0099
0100 static void xensyms_stop(struct seq_file *m, void *p)
0101 {
0102 }
0103
0104 static const struct seq_operations xensyms_seq_ops = {
0105 .start = xensyms_start,
0106 .next = xensyms_next,
0107 .show = xensyms_show,
0108 .stop = xensyms_stop,
0109 };
0110
0111 static int xensyms_open(struct inode *inode, struct file *file)
0112 {
0113 struct seq_file *m;
0114 struct xensyms *xs;
0115 int ret;
0116
0117 ret = seq_open_private(file, &xensyms_seq_ops,
0118 sizeof(struct xensyms));
0119 if (ret)
0120 return ret;
0121
0122 m = file->private_data;
0123 xs = (struct xensyms *)m->private;
0124
0125 xs->namelen = XEN_KSYM_NAME_LEN + 1;
0126 xs->name = kzalloc(xs->namelen, GFP_KERNEL);
0127 if (!xs->name) {
0128 seq_release_private(inode, file);
0129 return -ENOMEM;
0130 }
0131 set_xen_guest_handle(xs->op.u.symdata.name, xs->name);
0132 xs->op.cmd = XENPF_get_symbol;
0133 xs->op.u.symdata.namelen = xs->namelen;
0134
0135 return 0;
0136 }
0137
0138 static int xensyms_release(struct inode *inode, struct file *file)
0139 {
0140 struct seq_file *m = file->private_data;
0141 struct xensyms *xs = (struct xensyms *)m->private;
0142
0143 kfree(xs->name);
0144 return seq_release_private(inode, file);
0145 }
0146
0147 const struct file_operations xensyms_ops = {
0148 .open = xensyms_open,
0149 .read = seq_read,
0150 .llseek = seq_lseek,
0151 .release = xensyms_release
0152 };