common.h 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. #ifndef COMMON_H
  2. #define COMMON_H
  3. #define _XOPEN_SOURCE 700
  4. #include <fcntl.h> /* open */
  5. #include <stdint.h> /* uint64_t */
  6. #include <stdlib.h> /* size_t */
  7. #include <unistd.h> /* pread, sysconf */
  8. /* Format documented at:
  9. * https://github.com/torvalds/linux/blob/v4.9/Documentation/vm/pagemap.txt
  10. **/
  11. typedef struct {
  12. uint64_t pfn : 54;
  13. unsigned int soft_dirty : 1;
  14. unsigned int file_page : 1;
  15. unsigned int swapped : 1;
  16. unsigned int present : 1;
  17. } PagemapEntry;
  18. /* Parse the pagemap entry for the given virtual address.
  19. *
  20. * @param[out] entry the parsed entry
  21. * @param[in] pagemap_fd file descriptor to an open /proc/pid/pagemap file
  22. * @param[in] vaddr virtual address to get entry for
  23. * @return 0 for success, 1 for failure
  24. */
  25. int pagemap_get_entry(PagemapEntry *entry, int pagemap_fd, uintptr_t vaddr)
  26. {
  27. size_t nread;
  28. ssize_t ret;
  29. uint64_t data;
  30. nread = 0;
  31. while (nread < sizeof(data)) {
  32. ret = pread(pagemap_fd, &data, sizeof(data),
  33. (vaddr / sysconf(_SC_PAGE_SIZE)) * sizeof(data) + nread);
  34. nread += ret;
  35. if (ret <= 0) {
  36. return 1;
  37. }
  38. }
  39. entry->pfn = data & (((uint64_t)1 << 54) - 1);
  40. entry->soft_dirty = (data >> 54) & 1;
  41. entry->file_page = (data >> 61) & 1;
  42. entry->swapped = (data >> 62) & 1;
  43. entry->present = (data >> 63) & 1;
  44. return 0;
  45. }
  46. /* Convert the given virtual address to physical using /proc/PID/pagemap.
  47. *
  48. * @param[out] paddr physical address
  49. * @param[in] pid process to convert for
  50. * @param[in] vaddr virtual address to get entry for
  51. * @return 0 for success, 1 for failure
  52. */
  53. int virt_to_phys_user(uintptr_t *paddr, pid_t pid, uintptr_t vaddr)
  54. {
  55. char pagemap_file[BUFSIZ];
  56. int pagemap_fd;
  57. snprintf(pagemap_file, sizeof(pagemap_file), "/proc/%ju/pagemap", (uintmax_t)pid);
  58. pagemap_fd = open(pagemap_file, O_RDONLY);
  59. if (pagemap_fd < 0) {
  60. return 1;
  61. }
  62. PagemapEntry entry;
  63. if (pagemap_get_entry(&entry, pagemap_fd, vaddr)) {
  64. return 1;
  65. }
  66. close(pagemap_fd);
  67. *paddr = (entry.pfn * sysconf(_SC_PAGE_SIZE)) + (vaddr % sysconf(_SC_PAGE_SIZE));
  68. return 0;
  69. }
  70. #endif