pmemdump.cpp 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. /*
  2. * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/DeprecatedString.h>
  7. #include <AK/StringUtils.h>
  8. #include <LibCore/ArgsParser.h>
  9. #include <LibCore/System.h>
  10. #include <LibMain/Main.h>
  11. #include <assert.h>
  12. #include <errno.h>
  13. #include <fcntl.h>
  14. #include <inttypes.h>
  15. #include <stdio.h>
  16. #include <string.h>
  17. #include <sys/mman.h>
  18. #include <sys/stat.h>
  19. #include <unistd.h>
  20. static bool try_set_offset_and_length_parameters(DeprecatedString const& arg_offset, DeprecatedString const& arg_length, u64& offset, u64& length)
  21. {
  22. // TODO: Add support for hex values
  23. auto possible_offset = arg_offset.to_uint<u64>();
  24. if (!possible_offset.has_value())
  25. return false;
  26. auto possible_length = arg_length.to_uint<u64>();
  27. if (!possible_length.has_value())
  28. return false;
  29. offset = possible_offset.value();
  30. length = possible_length.value();
  31. return true;
  32. }
  33. static void try_to_dump_with_memory_mapping(int fd, u64 offset, u64 length)
  34. {
  35. VERIFY(fd >= 0);
  36. u64 mmoffset = offset % sysconf(_SC_PAGESIZE);
  37. void* mmp = mmap(NULL, mmoffset + length, PROT_READ, MAP_SHARED, fd, offset - mmoffset);
  38. if (mmp == MAP_FAILED) {
  39. perror("mmap");
  40. return;
  41. }
  42. size_t ncomplete = 0;
  43. while (ncomplete < length) {
  44. ssize_t nwritten = write(STDOUT_FILENO, static_cast<u8*>(mmp) + ncomplete, length - ncomplete);
  45. if (nwritten < 0) {
  46. perror("write");
  47. return;
  48. }
  49. ncomplete += nwritten;
  50. }
  51. if (munmap(mmp, mmoffset + length) < 0) {
  52. perror("munmap");
  53. }
  54. }
  55. static void try_to_dump_with_read(int fd, u64 offset, u64 length)
  56. {
  57. VERIFY(fd >= 0);
  58. auto rs = lseek(fd, offset, SEEK_SET);
  59. if (rs < 0) {
  60. fprintf(stderr, "Couldn't seek to offset %" PRIi64 " while verifying: %s\n", offset, strerror(errno));
  61. return;
  62. }
  63. u8 buf[4096];
  64. size_t ncomplete = 0;
  65. while (ncomplete < length) {
  66. size_t length_to_be_read = min<size_t>((length - ncomplete), sizeof(buf));
  67. if (read(fd, buf, length_to_be_read) < 0) {
  68. perror("read");
  69. return;
  70. }
  71. ssize_t nwritten = write(STDOUT_FILENO, buf, length_to_be_read);
  72. if (nwritten < 0) {
  73. perror("write");
  74. return;
  75. }
  76. ncomplete += nwritten;
  77. }
  78. }
  79. ErrorOr<int> serenity_main(Main::Arguments arguments)
  80. {
  81. TRY(Core::System::pledge("stdio rpath"));
  82. StringView arg_offset;
  83. StringView arg_length;
  84. bool use_read_instead_of_mmap = false;
  85. Core::ArgsParser args;
  86. args.add_positional_argument(arg_offset, "Physical Address (Offset)", "offset", Core::ArgsParser::Required::Yes);
  87. args.add_positional_argument(arg_length, "Length of that region", "length", Core::ArgsParser::Required::Yes);
  88. args.add_option(use_read_instead_of_mmap, "Read /dev/mem instead of try to map it", nullptr, 'r');
  89. args.parse(arguments);
  90. u64 offset = 0;
  91. u64 length = 0;
  92. if (!try_set_offset_and_length_parameters(arg_offset, arg_length, offset, length)) {
  93. warnln("pmemdump: Invalid length or offset parameters\n");
  94. return 1;
  95. }
  96. int fd = open("/dev/mem", O_RDONLY);
  97. if (fd < 0) {
  98. perror("open");
  99. return 1;
  100. }
  101. if (use_read_instead_of_mmap)
  102. try_to_dump_with_read(fd, offset, length);
  103. else
  104. try_to_dump_with_memory_mapping(fd, offset, length);
  105. close(fd);
  106. return 0;
  107. }