/* * dumpmem.c * * Yoann Guillot * 2005-10-16 * * takes a physical memory dump file, and dumps the content of a virtual memory range * from an offset in the physical memory to a PGD * * usage: dump [ ] */ #include #include #include #include #include #include #include #include #include typedef unsigned long u32; const void *ptr; // mmap(physdump) u32 sz; // physdump length void dump_mem(const u32 off, const u32 start, const u32 end) { const u32 *pgd = ptr + off; const u32 *pt; u32 i, j; char dumpfile[255]; int fd = -1; u32 raw, vstart, vend; #define closefd do { if (fd != -1) { close(fd); fd = -1; } } while (0) #define openfd(v) if (fd == -1) { \ snprintf(dumpfile, 255, "dmp-%.8lx_%.8lX", off, v); \ fd = open(dumpfile, O_WRONLY | O_CREAT | O_EXCL, 0644); \ if (fd == -1) { \ perror(dumpfile); \ continue; \ } } for (i = (start >> 22) ; i <= (end >> 22) ; i++) { // notpresent ? if (!(pgd[i] & 1)) { closefd; continue; } // 4M page ? if (pgd[i] & 0x80) { if (!(pgd[i] & 1)) { closefd; continue; } raw = pgd[i] & 0xFFC00000; vstart = (i << 22); vend = ((i+1) << 22) - 1; if (raw >= sz) { printf("big vpage %.8lX maps to %.8lX, outside physical memory\n", vstart, raw); continue; } if (vstart < start) { raw += start & 0x3FFFFF; vstart = start; } if (vend > end) vend = end; openfd(vstart); // printf("pgd[%lu] = %.8lX, dumping %.8lX-%.8lX from %.8lX\n", i, pgd[i], vstart, vend, raw); if (write(fd, ptr + raw, vend - vstart + 1) == -1) { perror("write"); closefd; } continue; } // 4k page raw = pgd[i] & 0xFFFFF000; if (raw >= sz) { fprintf(stderr, "invalid PGD: pde %lu (%.8lX) points outside memdump\n", i, pgd[i]); closefd; continue; } pt = ptr + raw; u32 jmin = 0, jmax = 1023; if (i == (start >> 22)) jmin = (start >> 12) & 0x3ff; if (i == (end >> 22)) jmax = (end >> 12) & 0x3ff; for (j=jmin ; j<=jmax ; j++) { if (!(pt[j] & 1)) { closefd; continue; } raw = pt[j] & 0xFFFFF000; vstart = (i << 22) + (j << 12); vend = (i << 22) + ((j+1) << 12) - 1; if (raw >= sz) { printf("vpage %.8lX maps to %.8lX, outside physical memory\n", vstart, raw); continue; } if (vstart < start) { raw += start & 0xFFF; vstart = start; } if (vend > end) vend = end; openfd(vstart); // printf("pgd[%lu] = %.8lX, pt[%lu] = %.8lX, dumping %.8lX-%.8lX from %.8lX\n", i, pgd[i], j, pt[j], vstart, vend, raw); if (write(fd, ptr + raw, vend - vstart + 1) == -1) { perror("write"); closefd; } } } closefd; } int main(int argc, char **argv) { u32 pgd; u32 start, end; if (argc < 3) { fprintf(stderr, "usage: %s [ ]\n", argv[0]); exit(1); } int fd = open(argv[1], O_RDONLY); if (fd == -1) { perror("open"); exit(1); } pgd = strtoul(argv[2], 0, 0); sz = 8*1024*1024; struct stat stat; if (!fstat(fd, &stat)) sz = stat.st_size; if ((pgd & 0xFFF) || (pgd >= sz)) { fprintf(stderr, "invalid pgd !\n"); return 1; } start = 0; end = 0xffffffff; if (argc > 3) start = strtoul(argv[3], 0, 0); if (argc > 4) end = strtoul(argv[4], 0, 0); ptr = mmap(0, sz, PROT_READ, MAP_PRIVATE, fd, 0); if (!ptr) { close(fd); perror("mmap"); exit(1); } dump_mem(pgd, start, end); munmap((void *)ptr, sz); close(fd); printf("done\n"); return 0; }