diff options
author | Boris Ostrovsky <boris.ostrovsky@oracle.com> | 2015-08-10 16:34:32 -0400 |
---|---|---|
committer | David Vrabel <david.vrabel@citrix.com> | 2015-08-20 07:24:25 -0400 |
commit | a11f4f0a4e18b4bdc7d5e36438711e038b7a1f74 (patch) | |
tree | 20319cffaee334bba06d8280b8398432097f9e65 | |
parent | cb3eb850137cd43fc3e25d2062525f5ba5fd884a (diff) |
xen: xensyms support
Export Xen symbols to dom0 via /proc/xen/xensyms (similar to
/proc/kallsyms).
Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Reviewed-by: David Vrabel <david.vrabel@citrix.com>
Signed-off-by: David Vrabel <david.vrabel@citrix.com>
-rw-r--r-- | drivers/xen/Kconfig | 8 | ||||
-rw-r--r-- | drivers/xen/xenfs/Makefile | 1 | ||||
-rw-r--r-- | drivers/xen/xenfs/super.c | 3 | ||||
-rw-r--r-- | drivers/xen/xenfs/xenfs.h | 1 | ||||
-rw-r--r-- | drivers/xen/xenfs/xensyms.c | 152 | ||||
-rw-r--r-- | include/xen/interface/platform.h | 18 |
6 files changed, 183 insertions, 0 deletions
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig index 7cd226da15fe..936760455dd5 100644 --- a/drivers/xen/Kconfig +++ b/drivers/xen/Kconfig | |||
@@ -280,4 +280,12 @@ config XEN_ACPI | |||
280 | def_bool y | 280 | def_bool y |
281 | depends on X86 && ACPI | 281 | depends on X86 && ACPI |
282 | 282 | ||
283 | config XEN_SYMS | ||
284 | bool "Xen symbols" | ||
285 | depends on X86 && XEN_DOM0 && XENFS | ||
286 | default y if KALLSYMS | ||
287 | help | ||
288 | Exports hypervisor symbols (along with their types and addresses) via | ||
289 | /proc/xen/xensyms file, similar to /proc/kallsyms | ||
290 | |||
283 | endmenu | 291 | endmenu |
diff --git a/drivers/xen/xenfs/Makefile b/drivers/xen/xenfs/Makefile index b019865fcc56..1a83010ddffa 100644 --- a/drivers/xen/xenfs/Makefile +++ b/drivers/xen/xenfs/Makefile | |||
@@ -2,3 +2,4 @@ obj-$(CONFIG_XENFS) += xenfs.o | |||
2 | 2 | ||
3 | xenfs-y = super.o | 3 | xenfs-y = super.o |
4 | xenfs-$(CONFIG_XEN_DOM0) += xenstored.o | 4 | xenfs-$(CONFIG_XEN_DOM0) += xenstored.o |
5 | xenfs-$(CONFIG_XEN_SYMS) += xensyms.o | ||
diff --git a/drivers/xen/xenfs/super.c b/drivers/xen/xenfs/super.c index 06092e0fe8ce..8559a71f36b1 100644 --- a/drivers/xen/xenfs/super.c +++ b/drivers/xen/xenfs/super.c | |||
@@ -57,6 +57,9 @@ static int xenfs_fill_super(struct super_block *sb, void *data, int silent) | |||
57 | { "privcmd", &xen_privcmd_fops, S_IRUSR|S_IWUSR }, | 57 | { "privcmd", &xen_privcmd_fops, S_IRUSR|S_IWUSR }, |
58 | { "xsd_kva", &xsd_kva_file_ops, S_IRUSR|S_IWUSR}, | 58 | { "xsd_kva", &xsd_kva_file_ops, S_IRUSR|S_IWUSR}, |
59 | { "xsd_port", &xsd_port_file_ops, S_IRUSR|S_IWUSR}, | 59 | { "xsd_port", &xsd_port_file_ops, S_IRUSR|S_IWUSR}, |
60 | #ifdef CONFIG_XEN_SYMS | ||
61 | { "xensyms", &xensyms_ops, S_IRUSR}, | ||
62 | #endif | ||
60 | {""}, | 63 | {""}, |
61 | }; | 64 | }; |
62 | 65 | ||
diff --git a/drivers/xen/xenfs/xenfs.h b/drivers/xen/xenfs/xenfs.h index 6b80c7779c02..2c5934ea9b1e 100644 --- a/drivers/xen/xenfs/xenfs.h +++ b/drivers/xen/xenfs/xenfs.h | |||
@@ -3,5 +3,6 @@ | |||
3 | 3 | ||
4 | extern const struct file_operations xsd_kva_file_ops; | 4 | extern const struct file_operations xsd_kva_file_ops; |
5 | extern const struct file_operations xsd_port_file_ops; | 5 | extern const struct file_operations xsd_port_file_ops; |
6 | extern const struct file_operations xensyms_ops; | ||
6 | 7 | ||
7 | #endif /* _XENFS_XENBUS_H */ | 8 | #endif /* _XENFS_XENBUS_H */ |
diff --git a/drivers/xen/xenfs/xensyms.c b/drivers/xen/xenfs/xensyms.c new file mode 100644 index 000000000000..f8b12856753f --- /dev/null +++ b/drivers/xen/xenfs/xensyms.c | |||
@@ -0,0 +1,152 @@ | |||
1 | #include <linux/module.h> | ||
2 | #include <linux/init.h> | ||
3 | #include <linux/seq_file.h> | ||
4 | #include <linux/fs.h> | ||
5 | #include <linux/mm.h> | ||
6 | #include <linux/proc_fs.h> | ||
7 | #include <linux/slab.h> | ||
8 | #include <xen/interface/platform.h> | ||
9 | #include <asm/xen/hypercall.h> | ||
10 | #include <xen/xen-ops.h> | ||
11 | #include "xenfs.h" | ||
12 | |||
13 | |||
14 | #define XEN_KSYM_NAME_LEN 127 /* Hypervisor may have different name length */ | ||
15 | |||
16 | struct xensyms { | ||
17 | struct xen_platform_op op; | ||
18 | char *name; | ||
19 | uint32_t namelen; | ||
20 | }; | ||
21 | |||
22 | /* Grab next output page from the hypervisor */ | ||
23 | static int xensyms_next_sym(struct xensyms *xs) | ||
24 | { | ||
25 | int ret; | ||
26 | struct xenpf_symdata *symdata = &xs->op.u.symdata; | ||
27 | uint64_t symnum; | ||
28 | |||
29 | memset(xs->name, 0, xs->namelen); | ||
30 | symdata->namelen = xs->namelen; | ||
31 | |||
32 | symnum = symdata->symnum; | ||
33 | |||
34 | ret = HYPERVISOR_dom0_op(&xs->op); | ||
35 | if (ret < 0) | ||
36 | return ret; | ||
37 | |||
38 | /* | ||
39 | * If hypervisor's symbol didn't fit into the buffer then allocate | ||
40 | * a larger buffer and try again. | ||
41 | */ | ||
42 | if (unlikely(symdata->namelen > xs->namelen)) { | ||
43 | kfree(xs->name); | ||
44 | |||
45 | xs->namelen = symdata->namelen; | ||
46 | xs->name = kzalloc(xs->namelen, GFP_KERNEL); | ||
47 | if (!xs->name) | ||
48 | return -ENOMEM; | ||
49 | |||
50 | set_xen_guest_handle(symdata->name, xs->name); | ||
51 | symdata->symnum--; /* Rewind */ | ||
52 | |||
53 | ret = HYPERVISOR_dom0_op(&xs->op); | ||
54 | if (ret < 0) | ||
55 | return ret; | ||
56 | } | ||
57 | |||
58 | if (symdata->symnum == symnum) | ||
59 | /* End of symbols */ | ||
60 | return 1; | ||
61 | |||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | static void *xensyms_start(struct seq_file *m, loff_t *pos) | ||
66 | { | ||
67 | struct xensyms *xs = (struct xensyms *)m->private; | ||
68 | |||
69 | xs->op.u.symdata.symnum = *pos; | ||
70 | |||
71 | if (xensyms_next_sym(xs)) | ||
72 | return NULL; | ||
73 | |||
74 | return m->private; | ||
75 | } | ||
76 | |||
77 | static void *xensyms_next(struct seq_file *m, void *p, loff_t *pos) | ||
78 | { | ||
79 | struct xensyms *xs = (struct xensyms *)m->private; | ||
80 | |||
81 | xs->op.u.symdata.symnum = ++(*pos); | ||
82 | |||
83 | if (xensyms_next_sym(xs)) | ||
84 | return NULL; | ||
85 | |||
86 | return p; | ||
87 | } | ||
88 | |||
89 | static int xensyms_show(struct seq_file *m, void *p) | ||
90 | { | ||
91 | struct xensyms *xs = (struct xensyms *)m->private; | ||
92 | struct xenpf_symdata *symdata = &xs->op.u.symdata; | ||
93 | |||
94 | seq_printf(m, "%016llx %c %s\n", symdata->address, | ||
95 | symdata->type, xs->name); | ||
96 | |||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | static void xensyms_stop(struct seq_file *m, void *p) | ||
101 | { | ||
102 | } | ||
103 | |||
104 | static const struct seq_operations xensyms_seq_ops = { | ||
105 | .start = xensyms_start, | ||
106 | .next = xensyms_next, | ||
107 | .show = xensyms_show, | ||
108 | .stop = xensyms_stop, | ||
109 | }; | ||
110 | |||
111 | static int xensyms_open(struct inode *inode, struct file *file) | ||
112 | { | ||
113 | struct seq_file *m; | ||
114 | struct xensyms *xs; | ||
115 | int ret; | ||
116 | |||
117 | ret = seq_open_private(file, &xensyms_seq_ops, | ||
118 | sizeof(struct xensyms)); | ||
119 | if (ret) | ||
120 | return ret; | ||
121 | |||
122 | m = file->private_data; | ||
123 | xs = (struct xensyms *)m->private; | ||
124 | |||
125 | xs->namelen = XEN_KSYM_NAME_LEN + 1; | ||
126 | xs->name = kzalloc(xs->namelen, GFP_KERNEL); | ||
127 | if (!xs->name) { | ||
128 | seq_release_private(inode, file); | ||
129 | return -ENOMEM; | ||
130 | } | ||
131 | set_xen_guest_handle(xs->op.u.symdata.name, xs->name); | ||
132 | xs->op.cmd = XENPF_get_symbol; | ||
133 | xs->op.u.symdata.namelen = xs->namelen; | ||
134 | |||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | static int xensyms_release(struct inode *inode, struct file *file) | ||
139 | { | ||
140 | struct seq_file *m = file->private_data; | ||
141 | struct xensyms *xs = (struct xensyms *)m->private; | ||
142 | |||
143 | kfree(xs->name); | ||
144 | return seq_release_private(inode, file); | ||
145 | } | ||
146 | |||
147 | const struct file_operations xensyms_ops = { | ||
148 | .open = xensyms_open, | ||
149 | .read = seq_read, | ||
150 | .llseek = seq_lseek, | ||
151 | .release = xensyms_release | ||
152 | }; | ||
diff --git a/include/xen/interface/platform.h b/include/xen/interface/platform.h index 5cc49ea8d840..8e035871360e 100644 --- a/include/xen/interface/platform.h +++ b/include/xen/interface/platform.h | |||
@@ -474,6 +474,23 @@ struct xenpf_core_parking { | |||
474 | }; | 474 | }; |
475 | DEFINE_GUEST_HANDLE_STRUCT(xenpf_core_parking); | 475 | DEFINE_GUEST_HANDLE_STRUCT(xenpf_core_parking); |
476 | 476 | ||
477 | #define XENPF_get_symbol 63 | ||
478 | struct xenpf_symdata { | ||
479 | /* IN/OUT variables */ | ||
480 | uint32_t namelen; /* size of 'name' buffer */ | ||
481 | |||
482 | /* IN/OUT variables */ | ||
483 | uint32_t symnum; /* IN: Symbol to read */ | ||
484 | /* OUT: Next available symbol. If same as IN */ | ||
485 | /* then we reached the end */ | ||
486 | |||
487 | /* OUT variables */ | ||
488 | GUEST_HANDLE(char) name; | ||
489 | uint64_t address; | ||
490 | char type; | ||
491 | }; | ||
492 | DEFINE_GUEST_HANDLE_STRUCT(xenpf_symdata); | ||
493 | |||
477 | struct xen_platform_op { | 494 | struct xen_platform_op { |
478 | uint32_t cmd; | 495 | uint32_t cmd; |
479 | uint32_t interface_version; /* XENPF_INTERFACE_VERSION */ | 496 | uint32_t interface_version; /* XENPF_INTERFACE_VERSION */ |
@@ -495,6 +512,7 @@ struct xen_platform_op { | |||
495 | struct xenpf_cpu_hotadd cpu_add; | 512 | struct xenpf_cpu_hotadd cpu_add; |
496 | struct xenpf_mem_hotadd mem_add; | 513 | struct xenpf_mem_hotadd mem_add; |
497 | struct xenpf_core_parking core_parking; | 514 | struct xenpf_core_parking core_parking; |
515 | struct xenpf_symdata symdata; | ||
498 | uint8_t pad[128]; | 516 | uint8_t pad[128]; |
499 | } u; | 517 | } u; |
500 | }; | 518 | }; |