├── .gitignore ├── LICENSE ├── Makefile ├── README.md └── memdump.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | /memdump 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Tom Hebb 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | EXECUTABLE = memdump 2 | OBJECTS = memdump.o 3 | 4 | CFLAGS = -Wall -Wextra -pedantic -std=c99 5 | 6 | all: $(EXECUTABLE) 7 | 8 | $(EXECUTABLE): $(OBJECTS) 9 | 10 | clean: 11 | -rm -f $(EXECUTABLE) $(OBJECTS) 12 | 13 | .PHONY: all clean 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | memdump 2 | ======= 3 | 4 | `memdump` is a (ridiculously simple) tool for dumping Linux I/O memory from 5 | `/dev/mem`, similar to `devmem2`. While `devmem2` is excellent at reading and 6 | poking at registers, it's not capable of dumping out a whole region of memory 7 | (a Boot ROM, for example). `memdump` is designed for just that. It's not able 8 | to write to memory or nicely format register values like `devmem2` can, though, 9 | so keep both tools handy. 10 | 11 | Building 12 | -------- 13 | Download. Run `make`. That's all. 14 | 15 | Limitations 16 | ----------- 17 | Obviously, `memdump` will only work with kernels that have `/dev/mem` enabled. 18 | Although it's great for dumping out I/O memory, `/dev/mem` can have problems 19 | with memory that's otherwise in use by the kernel, so expect trouble if you try 20 | to use this tool to dump process memory. Newer kernels are configured by 21 | default to explicitly forbid `/dev/mem` from accessing process memory, and 22 | you'll get an `Operation not permitted` message if you try. 23 | -------------------------------------------------------------------------------- /memdump.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | unsigned long parse_int (char *str); 12 | 13 | int main (int argc, char *argv[]) { 14 | unsigned long addr, length; 15 | 16 | int devmem; 17 | void *mapping; 18 | 19 | long page_size; 20 | off_t map_base, extra_bytes; 21 | 22 | char *buf; 23 | ssize_t ret; 24 | 25 | if (argc != 3) { 26 | fprintf(stderr, "Usage: %s ADDR LENGTH\n", argv[0]); 27 | exit(EXIT_FAILURE); 28 | } 29 | 30 | addr = parse_int(argv[1]); 31 | length = parse_int(argv[2]); 32 | 33 | devmem = open("/dev/mem", O_RDONLY); 34 | if (devmem == -1) { 35 | perror("Could not open /dev/mem"); 36 | goto open_fail; 37 | } 38 | 39 | page_size = sysconf(_SC_PAGE_SIZE); 40 | map_base = addr & ~(page_size - 1); 41 | extra_bytes = addr - map_base; 42 | 43 | mapping = mmap(NULL, length + extra_bytes, PROT_READ, MAP_SHARED, 44 | devmem, map_base); 45 | if (mapping == MAP_FAILED) { 46 | perror("Could not map memory"); 47 | goto map_fail; 48 | } 49 | 50 | buf = malloc(length); 51 | if (buf == NULL) { 52 | fprintf(stderr, "Failed to allocate memory\n"); 53 | goto alloc_fail; 54 | } 55 | 56 | /* 57 | * Using a separate buffer for write stops the kernel from 58 | * complaining quite as much as if we passed the mmap()ed 59 | * buffer directly to write(). 60 | */ 61 | memcpy(buf, (char *)mapping + extra_bytes, length); 62 | 63 | ret = write(STDOUT_FILENO, buf, length); 64 | if (ret == -1) { 65 | perror("Could not write data"); 66 | } else if (ret != (ssize_t)length) { 67 | fprintf(stderr, "Only wrote %zd bytes\n", ret); 68 | } 69 | 70 | free(buf); 71 | 72 | alloc_fail: 73 | munmap(mapping, length + extra_bytes); 74 | 75 | map_fail: 76 | close(devmem); 77 | 78 | open_fail: 79 | return EXIT_SUCCESS; 80 | } 81 | 82 | unsigned long parse_int (char *str) { 83 | long long result; 84 | char *endptr; 85 | 86 | result = strtoll(str, &endptr, 0); 87 | if (str[0] == '\0' || *endptr != '\0') { 88 | fprintf(stderr, "\"%s\" is not a valid number\n", str); 89 | exit(EXIT_FAILURE); 90 | } 91 | 92 | return (unsigned long)result; 93 | } 94 | --------------------------------------------------------------------------------