xensyms.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  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. #define XEN_KSYM_NAME_LEN 127 /* Hypervisor may have different name length */
  12. struct xensyms {
  13. struct xen_platform_op op;
  14. char *name;
  15. uint32_t namelen;
  16. };
  17. /* Grab next output page from the hypervisor */
  18. static int xensyms_next_sym(struct xensyms *xs)
  19. {
  20. int ret;
  21. struct xenpf_symdata *symdata = &xs->op.u.symdata;
  22. uint64_t symnum;
  23. memset(xs->name, 0, xs->namelen);
  24. symdata->namelen = xs->namelen;
  25. symnum = symdata->symnum;
  26. ret = HYPERVISOR_platform_op(&xs->op);
  27. if (ret < 0)
  28. return ret;
  29. /*
  30. * If hypervisor's symbol didn't fit into the buffer then allocate
  31. * a larger buffer and try again.
  32. */
  33. if (unlikely(symdata->namelen > xs->namelen)) {
  34. kfree(xs->name);
  35. xs->namelen = symdata->namelen;
  36. xs->name = kzalloc(xs->namelen, GFP_KERNEL);
  37. if (!xs->name)
  38. return -ENOMEM;
  39. set_xen_guest_handle(symdata->name, xs->name);
  40. symdata->symnum--; /* Rewind */
  41. ret = HYPERVISOR_platform_op(&xs->op);
  42. if (ret < 0)
  43. return ret;
  44. }
  45. if (symdata->symnum == symnum)
  46. /* End of symbols */
  47. return 1;
  48. return 0;
  49. }
  50. static void *xensyms_start(struct seq_file *m, loff_t *pos)
  51. {
  52. struct xensyms *xs = (struct xensyms *)m->private;
  53. xs->op.u.symdata.symnum = *pos;
  54. if (xensyms_next_sym(xs))
  55. return NULL;
  56. return m->private;
  57. }
  58. static void *xensyms_next(struct seq_file *m, void *p, loff_t *pos)
  59. {
  60. struct xensyms *xs = (struct xensyms *)m->private;
  61. xs->op.u.symdata.symnum = ++(*pos);
  62. if (xensyms_next_sym(xs))
  63. return NULL;
  64. return p;
  65. }
  66. static int xensyms_show(struct seq_file *m, void *p)
  67. {
  68. struct xensyms *xs = (struct xensyms *)m->private;
  69. struct xenpf_symdata *symdata = &xs->op.u.symdata;
  70. seq_printf(m, "%016llx %c %s\n", symdata->address,
  71. symdata->type, xs->name);
  72. return 0;
  73. }
  74. static void xensyms_stop(struct seq_file *m, void *p)
  75. {
  76. }
  77. static const struct seq_operations xensyms_seq_ops = {
  78. .start = xensyms_start,
  79. .next = xensyms_next,
  80. .show = xensyms_show,
  81. .stop = xensyms_stop,
  82. };
  83. static int xensyms_open(struct inode *inode, struct file *file)
  84. {
  85. struct seq_file *m;
  86. struct xensyms *xs;
  87. int ret;
  88. ret = seq_open_private(file, &xensyms_seq_ops,
  89. sizeof(struct xensyms));
  90. if (ret)
  91. return ret;
  92. m = file->private_data;
  93. xs = (struct xensyms *)m->private;
  94. xs->namelen = XEN_KSYM_NAME_LEN + 1;
  95. xs->name = kzalloc(xs->namelen, GFP_KERNEL);
  96. if (!xs->name) {
  97. seq_release_private(inode, file);
  98. return -ENOMEM;
  99. }
  100. set_xen_guest_handle(xs->op.u.symdata.name, xs->name);
  101. xs->op.cmd = XENPF_get_symbol;
  102. xs->op.u.symdata.namelen = xs->namelen;
  103. return 0;
  104. }
  105. static int xensyms_release(struct inode *inode, struct file *file)
  106. {
  107. struct seq_file *m = file->private_data;
  108. struct xensyms *xs = (struct xensyms *)m->private;
  109. kfree(xs->name);
  110. return seq_release_private(inode, file);
  111. }
  112. const struct file_operations xensyms_ops = {
  113. .open = xensyms_open,
  114. .read = seq_read,
  115. .llseek = seq_lseek,
  116. .release = xensyms_release
  117. };