diff --git a/CMakeLists.txt b/CMakeLists.txt index 53b401a..ccb289e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,6 +94,7 @@ install( man/fvc_kerndisp.3 man/fvc_open.3 man/fvc_read.3 + man/fvc_write.3 DESTINATION "${CMAKE_INSTALL_MANDIR}/man3") install( diff --git a/lib/fvc.c b/lib/fvc.c index e6b96c1..cac7158 100644 --- a/lib/fvc.c +++ b/lib/fvc.c @@ -154,7 +154,7 @@ _fvc_open(fvc_t *kd, const char *uf, const char *mf, char *errout) goto failed; } - if ((kd->pmfd = open(mf, O_RDONLY | O_CLOEXEC, 0)) < 0) { + if ((kd->pmfd = open(mf, O_RDWR | O_CLOEXEC, 0)) < 0) { _fvc_syserr(kd, kd->program, "%s", mf); goto failed; } @@ -297,6 +297,47 @@ fvc_read(fvc_t *kd, fvc_addr_t kva, void *buf, size_t len) _fvc_syserr(kd, kd->program, "fvc_read"); break; } + printf("%% RD: %zu %d\n", pa, cc); + /* + * If ka_kvatop returns a bogus value or our core file is + * truncated, we might wind up seeking beyond the end of the + * core file in which case the read will return 0 (EOF). + */ + if (cr == 0) + break; + cp += cr; + kva += cr; + len -= cr; + } + + return (cp - (char *)buf); +} + +ssize_t +fvc_write(fvc_t *kd, fvc_addr_t kva, const void *buf, size_t len) +{ + int cc; + ssize_t cr; + off_t pa; + const char *cp; + + cp = buf; + while (len > 0) { + cc = kd->arch->ka_kvatop(kd, kva, &pa); + if (cc == 0) + return (-1); + if (cc > (ssize_t)len) + cc = len; + errno = 0; + if (lseek(kd->pmfd, pa, 0) == -1 && errno != 0) { + _fvc_syserr(kd, 0, _PATH_MEM); + break; + } + cr = write(kd->pmfd, cp, cc); + if (cr < 0) { + _fvc_syserr(kd, kd->program, "fvc_write"); + break; + } /* * If ka_kvatop returns a bogus value or our core file is * truncated, we might wind up seeking beyond the end of the @@ -331,3 +372,8 @@ fvc_kerndisp(fvc_t *kd) return (kd->arch->ka_kerndisp(kd)); } + +ssize_t xpread(int fd, void *buf, size_t count, off_t offset) { + printf("%% RD: %zu %zu\n", offset, count); + return pread(fd, buf, count, offset); +} diff --git a/lib/fvc.h b/lib/fvc.h index 8680079..8cff17c 100644 --- a/lib/fvc.h +++ b/lib/fvc.h @@ -54,6 +54,8 @@ typedef unsigned char fvc_vm_prot_t; #define FVC_VM_PROT_WRITE ((fvc_vm_prot_t) 0x02) #define FVC_VM_PROT_EXECUTE ((fvc_vm_prot_t) 0x04) +ssize_t xpread(int fd, void *buf, size_t count, off_t offset); + struct fvc_page { unsigned int kp_version; fvc_addr_t kp_paddr; @@ -76,6 +78,7 @@ fvc_t *fvc_open (const char *, const char *, char *, int (*)(const char *, fvc_addr_t *, void *), void *); ssize_t fvc_read(fvc_t *, fvc_addr_t, void *, size_t); +ssize_t fvc_write(fvc_t *, fvc_addr_t, const void *, size_t); ssize_t fvc_kerndisp(fvc_t *); typedef int fvc_walk_pages_cb_t(struct fvc_page *, void *); diff --git a/lib/fvc_amd64.c b/lib/fvc_amd64.c index 4d27998..69f1807 100644 --- a/lib/fvc_amd64.c +++ b/lib/fvc_amd64.c @@ -205,7 +205,7 @@ _amd64_vatop(fvc_t *kd, fvc_addr_t va, off_t *pa) _fvc_err(kd, kd->program, "_amd64_vatop: pdpe_pa not found"); goto invalid; } - if (pread(kd->pmfd, &pdpe, sizeof(pdpe), ofs) != sizeof(pdpe)) { + if (xpread(kd->pmfd, &pdpe, sizeof(pdpe), ofs) != sizeof(pdpe)) { _fvc_syserr(kd, kd->program, "_amd64_vatop: read pdpe"); goto invalid; } @@ -237,7 +237,7 @@ _amd64_vatop(fvc_t *kd, fvc_addr_t va, off_t *pa) _fvc_syserr(kd, kd->program, "_amd64_vatop: pde_pa not found"); goto invalid; } - if (pread(kd->pmfd, &pde, sizeof(pde), ofs) != sizeof(pde)) { + if (xpread(kd->pmfd, &pde, sizeof(pde), ofs) != sizeof(pde)) { _fvc_syserr(kd, kd->program, "_amd64_vatop: read pde"); goto invalid; } @@ -269,7 +269,7 @@ _amd64_vatop(fvc_t *kd, fvc_addr_t va, off_t *pa) _fvc_err(kd, kd->program, "_amd64_vatop: pte_pa not found"); goto invalid; } - if (pread(kd->pmfd, &pte, sizeof(pte), ofs) != sizeof(pte)) { + if (xpread(kd->pmfd, &pte, sizeof(pte), ofs) != sizeof(pte)) { _fvc_syserr(kd, kd->program, "_amd64_vatop: read"); goto invalid; } diff --git a/lib/fvc_minidump_aarch64.c b/lib/fvc_minidump_aarch64.c index 4b8477a..a1c5b42 100644 --- a/lib/fvc_minidump_aarch64.c +++ b/lib/fvc_minidump_aarch64.c @@ -86,7 +86,7 @@ _aarch64_minidump_initvtop(fvc_t *kd) return (-1); } kd->vmst = vmst; - if (pread(kd->pmfd, &vmst->hdr, sizeof(vmst->hdr), 0) != + if (xpread(kd->pmfd, &vmst->hdr, sizeof(vmst->hdr), 0) != sizeof(vmst->hdr)) { _fvc_err(kd, kd->program, "cannot read dump header"); return (-1); diff --git a/lib/fvc_minidump_amd64.c b/lib/fvc_minidump_amd64.c index 93e8238..0d2237f 100644 --- a/lib/fvc_minidump_amd64.c +++ b/lib/fvc_minidump_amd64.c @@ -126,7 +126,7 @@ _amd64_minidump_initvtop(fvc_t *kd) return (-1); } kd->vmst = vmst; - if (pread(kd->pmfd, &vmst->hdr, sizeof(vmst->hdr), 0) != + if (xpread(kd->pmfd, &vmst->hdr, sizeof(vmst->hdr), 0) != sizeof(vmst->hdr)) { _fvc_err(kd, kd->program, "cannot read dump header"); return (-1); @@ -269,7 +269,7 @@ _amd64_minidump_vatop(fvc_t *kd, fvc_addr_t va, off_t *pa) (uintmax_t)a); goto invalid; } - if (pread(kd->pmfd, &pt, AMD64_PAGE_SIZE, ofs) != + if (xpread(kd->pmfd, &pt, AMD64_PAGE_SIZE, ofs) != AMD64_PAGE_SIZE) { _fvc_err(kd, kd->program, "cannot read page table entry for %ju", diff --git a/lib/fvc_minidump_i386.c b/lib/fvc_minidump_i386.c index 61cc3db..b3ab955 100644 --- a/lib/fvc_minidump_i386.c +++ b/lib/fvc_minidump_i386.c @@ -94,7 +94,7 @@ _i386_minidump_initvtop(fvc_t *kd) return (-1); } kd->vmst = vmst; - if (pread(kd->pmfd, &vmst->hdr, sizeof(vmst->hdr), 0) != + if (xpread(kd->pmfd, &vmst->hdr, sizeof(vmst->hdr), 0) != sizeof(vmst->hdr)) { _fvc_err(kd, kd->program, "cannot read dump header"); return (-1); diff --git a/lib/fvc_private.c b/lib/fvc_private.c index 0069a54..fc798fe 100644 --- a/lib/fvc_private.c +++ b/lib/fvc_private.c @@ -130,7 +130,7 @@ _fvc_is_minidump(fvc_t *kd) { char minihdr[8]; - if (pread(kd->pmfd, &minihdr, 8, 0) == 8 && + if (xpread(kd->pmfd, &minihdr, 8, 0) == 8 && memcmp(&minihdr, "minidump", 8) == 0) return (1); return (0); @@ -256,6 +256,7 @@ _fvc_pmap_get(fvc_t *kd, u_long idx, size_t len) if ((off_t)off >= kd->pt_sparse_off) return (NULL); + printf("%% RD: %zu %zu\n", kd->page_map_off+off, len); return (void *)((uintptr_t)kd->page_map + off); } @@ -270,8 +271,13 @@ _fvc_map_get(fvc_t *kd, u_long pa, unsigned int page_size) return NULL; addr = (uintptr_t)kd->page_map + off; - if (off >= kd->pt_sparse_off) + if (off >= kd->pt_sparse_off) { + addr = (uintptr_t)kd->sparse_map + (off - kd->pt_sparse_off); + printf("%% RD: %zu %u\n", off, page_size); + } + else + printf("%% RD: %zu %u\n", kd->page_map_off+off, page_size); return (void *)addr; } @@ -289,6 +295,7 @@ _fvc_pt_init(fvc_t *kd, size_t dump_avail_size, off_t dump_avail_off, if (dump_avail_size > 0) { kd->dump_avail = mmap(NULL, kd->dump_avail_size, PROT_READ, MAP_PRIVATE, kd->pmfd, dump_avail_off); + printf("%% RD: %zu %zu\n", dump_avail_off, dump_avail_size); } else { /* * Older version minidumps don't provide dump_avail[], @@ -309,7 +316,7 @@ _fvc_pt_init(fvc_t *kd, size_t dump_avail_size, off_t dump_avail_off, map_len); return (-1); } - rd = pread(kd->pmfd, kd->pt_map, map_len, map_off); + rd = xpread(kd->pmfd, kd->pt_map, map_len, map_off); if (rd < 0 || rd != (ssize_t)map_len) { _fvc_err(kd, kd->program, "cannot read %zu bytes for bitmap", map_len); diff --git a/man/fbsdvmcore.3 b/man/fbsdvmcore.3 index 4285ba2..c0d760c 100644 --- a/man/fbsdvmcore.3 +++ b/man/fbsdvmcore.3 @@ -89,4 +89,5 @@ etc. .Xr fvc_geterr 3 , .Xr fvc_kerndisp 3 , .Xr fvc_open 3 , -.Xr fvc_read 3 +.Xr fvc_read 3 , +.Xr fvc_write 3 diff --git a/man/fvc_geterr.3 b/man/fvc_geterr.3 index 964a097..7d74c25 100644 --- a/man/fvc_geterr.3 +++ b/man/fvc_geterr.3 @@ -66,7 +66,8 @@ or an error has not been captured for .Sh SEE ALSO .Xr fvc 3 , .Xr fvc_close 3 , -.Xr fvc_read 3 +.Xr fvc_read 3 , +.Xr fvc_write 3 .Sh BUGS This routine cannot be used to access error conditions due to a failed .Fn fvc_open diff --git a/man/fvc_open.3 b/man/fvc_open.3 index 1f8e3be..4ea93ed 100644 --- a/man/fvc_open.3 +++ b/man/fvc_open.3 @@ -166,5 +166,6 @@ was .Xr fvc_geterr 3 , .Xr fvc_native 3 , .Xr fvc_read 3 , +.Xr fvc_write 3 , .Xr kmem 4 , .Xr mem 4 diff --git a/man/fvc_read.3 b/man/fvc_read.3 index 7413d59..c18dadc 100644 --- a/man/fvc_read.3 +++ b/man/fvc_read.3 @@ -36,18 +36,24 @@ .Dt FVC_READ 3 .Os .Sh NAME -.Nm fvc_read -.Nd read kernel virtual memory +.Nm fvc_read , +.Nm fvc_write +.Nd read or write kernel virtual memory .Sh LIBRARY .Lb libfbsdvmcore .Sh SYNOPSIS .In fvc.h .Ft ssize_t .Fn fvc_read "fvc_t *kd" "kvaddr_t addr" "void *buf" "size_t nbytes" +.Ft ssize_t +.Fn fvc_write "fvc_t *kd" "kvaddr_t addr" "void *buf" "size_t nbytes" .Sh DESCRIPTION The .Fn fvc_read function is used to read a crash dump file. +.Fn fvc_write +function is used to overwrite parts of a crash dump file. +Note that only the fragments already present can be written. See .Fn fvc_open 3 for information regarding opening kernel crash dumps. @@ -63,6 +69,13 @@ to .Fa buf . .Pp The +.Fn fvc_write +function transfers +.Fa nbytes +bytes of data from +.Fa buf +to the kernel space address +.Fa addr . .Sh RETURN VALUES Upon success, the number of bytes actually transferred is returned. Otherwise, -1 is returned. diff --git a/man/fvc_write.3 b/man/fvc_write.3 new file mode 100644 index 0000000..f25fc74 --- /dev/null +++ b/man/fvc_write.3 @@ -0,0 +1 @@ +.so man3/fvc_read.3