summaryrefslogtreecommitdiff
path: root/Userland/Utilities/pmemdump.cpp
diff options
context:
space:
mode:
authorLiav A <liavalb@gmail.com>2021-12-24 07:04:34 +0200
committerIdan Horowitz <idan.horowitz@gmail.com>2022-01-08 13:21:16 +0200
commitff25958b5110432afabf16d01ee2b61e39de5f37 (patch)
treecd34b0ef1baa983b5d48018aee7a1cffe6f9cb09 /Userland/Utilities/pmemdump.cpp
parentf7d1b8cd0cba181b19eb10872ef2e84751af3733 (diff)
downloadserenity-ff25958b5110432afabf16d01ee2b61e39de5f37.zip
Userland: Introduce the pmemdump utility
This utility helps to dump the physical memory space from /dev/mem. It supports both read(2) and mmap(2) on it so we could use mmap(2) for fast dumping of the memory, or read(2) when we need to read unaligned physical regions.
Diffstat (limited to 'Userland/Utilities/pmemdump.cpp')
-rw-r--r--Userland/Utilities/pmemdump.cpp120
1 files changed, 120 insertions, 0 deletions
diff --git a/Userland/Utilities/pmemdump.cpp b/Userland/Utilities/pmemdump.cpp
new file mode 100644
index 0000000000..09b58e22eb
--- /dev/null
+++ b/Userland/Utilities/pmemdump.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <AK/String.h>
+#include <AK/StringUtils.h>
+#include <LibCore/ArgsParser.h>
+#include <LibCore/System.h>
+#include <LibMain/Main.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+static bool try_set_offset_and_length_parameters(String const& arg_offset, String const& arg_length, u64& offset, u64& length)
+{
+ // TODO: Add support for hex values
+ auto possible_offset = arg_offset.to_uint<u64>();
+ if (!possible_offset.has_value())
+ return false;
+ auto possible_length = arg_length.to_uint<u64>();
+ if (!possible_length.has_value())
+ return false;
+ offset = possible_offset.value();
+ length = possible_length.value();
+ return true;
+}
+
+static void try_to_dump_with_memory_mapping(int fd, u64 offset, u64 length)
+{
+ VERIFY(fd >= 0);
+ u64 mmoffset = offset % sysconf(_SC_PAGESIZE);
+ void* mmp = mmap(NULL, mmoffset + length, PROT_READ, MAP_SHARED, fd, offset - mmoffset);
+ if (mmp == MAP_FAILED) {
+ perror("mmap");
+ return;
+ }
+
+ size_t ncomplete = 0;
+ while (ncomplete < length) {
+ ssize_t nwritten = write(STDOUT_FILENO, static_cast<u8*>(mmp) + ncomplete, length - ncomplete);
+ if (nwritten < 0) {
+ perror("write");
+ return;
+ }
+ ncomplete += nwritten;
+ }
+ if (munmap(mmp, mmoffset + length) < 0) {
+ perror("munmap");
+ }
+}
+
+static void try_to_dump_with_read(int fd, u64 offset, u64 length)
+{
+ VERIFY(fd >= 0);
+ auto rs = lseek(fd, offset, SEEK_SET);
+ if (rs < 0) {
+ fprintf(stderr, "Couldn't seek to offset %" PRIi64 " while verifying: %s\n", offset, strerror(errno));
+ return;
+ }
+ u8 buf[4096];
+ size_t ncomplete = 0;
+ while (ncomplete < length) {
+ size_t length_to_be_read = min<size_t>((length - ncomplete), sizeof(buf));
+ if (read(fd, buf, length_to_be_read) < 0) {
+ perror("read");
+ return;
+ }
+ ssize_t nwritten = write(STDOUT_FILENO, buf, length_to_be_read);
+ if (nwritten < 0) {
+ perror("write");
+ return;
+ }
+ ncomplete += nwritten;
+ }
+}
+
+ErrorOr<int> serenity_main(Main::Arguments arguments)
+{
+ TRY(Core::System::pledge("stdio rpath"));
+
+ StringView arg_offset;
+ StringView arg_length;
+ bool use_read_instead_of_mmap = false;
+ Core::ArgsParser args;
+ args.add_positional_argument(arg_offset, "Physical Address (Offset)", "offset", Core::ArgsParser::Required::Yes);
+ args.add_positional_argument(arg_length, "Length of that region", "length", Core::ArgsParser::Required::Yes);
+ args.add_option(use_read_instead_of_mmap, "Read /dev/mem instead of try to map it", nullptr, 'r');
+
+ args.parse(arguments);
+
+ u64 offset = 0;
+ u64 length = 0;
+ if (!try_set_offset_and_length_parameters(arg_offset, arg_length, offset, length)) {
+ warnln("pmemdump: Invalid length or offset parameters\n");
+ return 1;
+ }
+
+ int fd = open("/dev/mem", O_RDONLY);
+ if (fd < 0) {
+ perror("open");
+ return 1;
+ }
+ if (use_read_instead_of_mmap)
+ try_to_dump_with_read(fd, offset, length);
+ else
+ try_to_dump_with_memory_mapping(fd, offset, length);
+
+ close(fd);
+
+ return 0;
+}