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