pagemap_dump.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. /* https://cirosantilli.com/linux-kernel-module-cheat#pagemap-dump-out */
  2. #define _XOPEN_SOURCE 700
  3. #include <errno.h>
  4. #include <fcntl.h>
  5. #include <stdint.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <sys/types.h>
  9. #include <unistd.h>
  10. #include <lkmc/pagemap.h> /* lkmc_pagemap_virt_to_phys_user */
  11. int main(int argc, char **argv) {
  12. char buffer[BUFSIZ];
  13. char maps_file[BUFSIZ];
  14. char pagemap_file[BUFSIZ];
  15. int maps_fd;
  16. int offset = 0;
  17. int pagemap_fd;
  18. pid_t pid;
  19. if (argc < 2) {
  20. printf("Usage: %s pid\n", argv[0]);
  21. return EXIT_FAILURE;
  22. }
  23. pid = strtoull(argv[1], NULL, 0);
  24. snprintf(maps_file, sizeof(maps_file), "/proc/%ju/maps", (uintmax_t)pid);
  25. snprintf(pagemap_file, sizeof(pagemap_file), "/proc/%ju/pagemap", (uintmax_t)pid);
  26. maps_fd = open(maps_file, O_RDONLY);
  27. if (maps_fd < 0) {
  28. perror("open maps");
  29. return EXIT_FAILURE;
  30. }
  31. pagemap_fd = open(pagemap_file, O_RDONLY);
  32. if (pagemap_fd < 0) {
  33. perror("open pagemap");
  34. return EXIT_FAILURE;
  35. }
  36. printf("vaddr pfn soft-dirty file/shared swapped present library\n");
  37. for (;;) {
  38. ssize_t length = read(maps_fd, buffer + offset, sizeof buffer - offset);
  39. if (length <= 0) break;
  40. length += offset;
  41. for (size_t i = offset; i < (size_t)length; i++) {
  42. uintptr_t low = 0, high = 0;
  43. if (buffer[i] == '\n' && i) {
  44. const char *lib_name;
  45. size_t y;
  46. /* Parse a line from maps. Each line contains a range that contains many pages. */
  47. {
  48. size_t x = i - 1;
  49. while (x && buffer[x] != '\n') x--;
  50. if (buffer[x] == '\n') x++;
  51. while (buffer[x] != '-' && x < sizeof buffer) {
  52. char c = buffer[x++];
  53. low *= 16;
  54. if (c >= '0' && c <= '9') {
  55. low += c - '0';
  56. } else if (c >= 'a' && c <= 'f') {
  57. low += c - 'a' + 10;
  58. } else {
  59. break;
  60. }
  61. }
  62. while (buffer[x] != '-' && x < sizeof buffer) x++;
  63. if (buffer[x] == '-') x++;
  64. while (buffer[x] != ' ' && x < sizeof buffer) {
  65. char c = buffer[x++];
  66. high *= 16;
  67. if (c >= '0' && c <= '9') {
  68. high += c - '0';
  69. } else if (c >= 'a' && c <= 'f') {
  70. high += c - 'a' + 10;
  71. } else {
  72. break;
  73. }
  74. }
  75. lib_name = 0;
  76. for (int field = 0; field < 4; field++) {
  77. x++;
  78. while(buffer[x] != ' ' && x < sizeof buffer) x++;
  79. }
  80. while (buffer[x] == ' ' && x < sizeof buffer) x++;
  81. y = x;
  82. while (buffer[y] != '\n' && y < sizeof buffer) y++;
  83. buffer[y] = 0;
  84. lib_name = buffer + x;
  85. }
  86. /* Get info about all pages in this page range with pagemap. */
  87. {
  88. LkmcPagemapEntry entry;
  89. for (uintptr_t vaddr = low; vaddr < high; vaddr += sysconf(_SC_PAGE_SIZE)) {
  90. /* TODO always fails for the last page (vsyscall), why? pread returns 0. */
  91. if (!lkmc_pagemap_get_entry(&entry, pagemap_fd, vaddr)) {
  92. printf(
  93. "%jx %jx %u %u %u %u %s\n",
  94. (uintmax_t)vaddr,
  95. (uintmax_t)entry.pfn,
  96. entry.soft_dirty,
  97. entry.file_page,
  98. entry.swapped,
  99. entry.present,
  100. lib_name
  101. );
  102. }
  103. }
  104. }
  105. buffer[y] = '\n';
  106. }
  107. }
  108. }
  109. close(maps_fd);
  110. close(pagemap_fd);
  111. return EXIT_SUCCESS;
  112. }