1diff --git a/CMakeLists.txt b/CMakeLists.txt 2index 53b401a..ccb289e 100644 3--- a/CMakeLists.txt 4+++ b/CMakeLists.txt 5@@ -94,6 +94,7 @@ install( 6 man/fvc_kerndisp.3 7 man/fvc_open.3 8 man/fvc_read.3 9+ man/fvc_write.3 10 DESTINATION "${CMAKE_INSTALL_MANDIR}/man3") 11 12 install( 13diff --git a/lib/fvc.c b/lib/fvc.c 14index e6b96c1..cac7158 100644 15--- a/lib/fvc.c 16+++ b/lib/fvc.c 17@@ -154,7 +154,7 @@ _fvc_open(fvc_t *kd, const char *uf, const char *mf, char *errout) 18 goto failed; 19 } 20 21- if ((kd->pmfd = open(mf, O_RDONLY | O_CLOEXEC, 0)) < 0) { 22+ if ((kd->pmfd = open(mf, O_RDWR | O_CLOEXEC, 0)) < 0) { 23 _fvc_syserr(kd, kd->program, "%s", mf); 24 goto failed; 25 } 26@@ -297,6 +297,47 @@ fvc_read(fvc_t *kd, fvc_addr_t kva, void *buf, size_t len) 27 _fvc_syserr(kd, kd->program, "fvc_read"); 28 break; 29 } 30+ printf("%% RD: %zu %d\n", pa, cc); 31+ /* 32+ * If ka_kvatop returns a bogus value or our core file is 33+ * truncated, we might wind up seeking beyond the end of the 34+ * core file in which case the read will return 0 (EOF). 35+ */ 36+ if (cr == 0) 37+ break; 38+ cp += cr; 39+ kva += cr; 40+ len -= cr; 41+ } 42+ 43+ return (cp - (char *)buf); 44+} 45+ 46+ssize_t 47+fvc_write(fvc_t *kd, fvc_addr_t kva, const void *buf, size_t len) 48+{ 49+ int cc; 50+ ssize_t cr; 51+ off_t pa; 52+ const char *cp; 53+ 54+ cp = buf; 55+ while (len > 0) { 56+ cc = kd->arch->ka_kvatop(kd, kva, &pa); 57+ if (cc == 0) 58+ return (-1); 59+ if (cc > (ssize_t)len) 60+ cc = len; 61+ errno = 0; 62+ if (lseek(kd->pmfd, pa, 0) == -1 && errno != 0) { 63+ _fvc_syserr(kd, 0, _PATH_MEM); 64+ break; 65+ } 66+ cr = write(kd->pmfd, cp, cc); 67+ if (cr < 0) { 68+ _fvc_syserr(kd, kd->program, "fvc_write"); 69+ break; 70+ } 71 /* 72 * If ka_kvatop returns a bogus value or our core file is 73 * truncated, we might wind up seeking beyond the end of the 74@@ -331,3 +372,8 @@ fvc_kerndisp(fvc_t *kd) 75 76 return (kd->arch->ka_kerndisp(kd)); 77 } 78+ 79+ssize_t xpread(int fd, void *buf, size_t count, off_t offset) { 80+ printf("%% RD: %zu %zu\n", offset, count); 81+ return pread(fd, buf, count, offset); 82+} 83diff --git a/lib/fvc.h b/lib/fvc.h 84index 8680079..8cff17c 100644 85--- a/lib/fvc.h 86+++ b/lib/fvc.h 87@@ -54,6 +54,8 @@ typedef unsigned char fvc_vm_prot_t; 88 #define FVC_VM_PROT_WRITE ((fvc_vm_prot_t) 0x02) 89 #define FVC_VM_PROT_EXECUTE ((fvc_vm_prot_t) 0x04) 90 91+ssize_t xpread(int fd, void *buf, size_t count, off_t offset); 92+ 93 struct fvc_page { 94 unsigned int kp_version; 95 fvc_addr_t kp_paddr; 96@@ -76,6 +78,7 @@ fvc_t *fvc_open 97 (const char *, const char *, char *, 98 int (*)(const char *, fvc_addr_t *, void *), void *); 99 ssize_t fvc_read(fvc_t *, fvc_addr_t, void *, size_t); 100+ssize_t fvc_write(fvc_t *, fvc_addr_t, const void *, size_t); 101 ssize_t fvc_kerndisp(fvc_t *); 102 103 typedef int fvc_walk_pages_cb_t(struct fvc_page *, void *); 104diff --git a/lib/fvc_amd64.c b/lib/fvc_amd64.c 105index 4d27998..69f1807 100644 106--- a/lib/fvc_amd64.c 107+++ b/lib/fvc_amd64.c 108@@ -205,7 +205,7 @@ _amd64_vatop(fvc_t *kd, fvc_addr_t va, off_t *pa) 109 _fvc_err(kd, kd->program, "_amd64_vatop: pdpe_pa not found"); 110 goto invalid; 111 } 112- if (pread(kd->pmfd, &pdpe, sizeof(pdpe), ofs) != sizeof(pdpe)) { 113+ if (xpread(kd->pmfd, &pdpe, sizeof(pdpe), ofs) != sizeof(pdpe)) { 114 _fvc_syserr(kd, kd->program, "_amd64_vatop: read pdpe"); 115 goto invalid; 116 } 117@@ -237,7 +237,7 @@ _amd64_vatop(fvc_t *kd, fvc_addr_t va, off_t *pa) 118 _fvc_syserr(kd, kd->program, "_amd64_vatop: pde_pa not found"); 119 goto invalid; 120 } 121- if (pread(kd->pmfd, &pde, sizeof(pde), ofs) != sizeof(pde)) { 122+ if (xpread(kd->pmfd, &pde, sizeof(pde), ofs) != sizeof(pde)) { 123 _fvc_syserr(kd, kd->program, "_amd64_vatop: read pde"); 124 goto invalid; 125 } 126@@ -269,7 +269,7 @@ _amd64_vatop(fvc_t *kd, fvc_addr_t va, off_t *pa) 127 _fvc_err(kd, kd->program, "_amd64_vatop: pte_pa not found"); 128 goto invalid; 129 } 130- if (pread(kd->pmfd, &pte, sizeof(pte), ofs) != sizeof(pte)) { 131+ if (xpread(kd->pmfd, &pte, sizeof(pte), ofs) != sizeof(pte)) { 132 _fvc_syserr(kd, kd->program, "_amd64_vatop: read"); 133 goto invalid; 134 } 135diff --git a/lib/fvc_minidump_aarch64.c b/lib/fvc_minidump_aarch64.c 136index 4b8477a..a1c5b42 100644 137--- a/lib/fvc_minidump_aarch64.c 138+++ b/lib/fvc_minidump_aarch64.c 139@@ -86,7 +86,7 @@ _aarch64_minidump_initvtop(fvc_t *kd) 140 return (-1); 141 } 142 kd->vmst = vmst; 143- if (pread(kd->pmfd, &vmst->hdr, sizeof(vmst->hdr), 0) != 144+ if (xpread(kd->pmfd, &vmst->hdr, sizeof(vmst->hdr), 0) != 145 sizeof(vmst->hdr)) { 146 _fvc_err(kd, kd->program, "cannot read dump header"); 147 return (-1); 148diff --git a/lib/fvc_minidump_amd64.c b/lib/fvc_minidump_amd64.c 149index 93e8238..0d2237f 100644 150--- a/lib/fvc_minidump_amd64.c 151+++ b/lib/fvc_minidump_amd64.c 152@@ -126,7 +126,7 @@ _amd64_minidump_initvtop(fvc_t *kd) 153 return (-1); 154 } 155 kd->vmst = vmst; 156- if (pread(kd->pmfd, &vmst->hdr, sizeof(vmst->hdr), 0) != 157+ if (xpread(kd->pmfd, &vmst->hdr, sizeof(vmst->hdr), 0) != 158 sizeof(vmst->hdr)) { 159 _fvc_err(kd, kd->program, "cannot read dump header"); 160 return (-1); 161@@ -269,7 +269,7 @@ _amd64_minidump_vatop(fvc_t *kd, fvc_addr_t va, off_t *pa) 162 (uintmax_t)a); 163 goto invalid; 164 } 165- if (pread(kd->pmfd, &pt, AMD64_PAGE_SIZE, ofs) != 166+ if (xpread(kd->pmfd, &pt, AMD64_PAGE_SIZE, ofs) != 167 AMD64_PAGE_SIZE) { 168 _fvc_err(kd, kd->program, 169 "cannot read page table entry for %ju", 170diff --git a/lib/fvc_minidump_i386.c b/lib/fvc_minidump_i386.c 171index 61cc3db..b3ab955 100644 172--- a/lib/fvc_minidump_i386.c 173+++ b/lib/fvc_minidump_i386.c 174@@ -94,7 +94,7 @@ _i386_minidump_initvtop(fvc_t *kd) 175 return (-1); 176 } 177 kd->vmst = vmst; 178- if (pread(kd->pmfd, &vmst->hdr, sizeof(vmst->hdr), 0) != 179+ if (xpread(kd->pmfd, &vmst->hdr, sizeof(vmst->hdr), 0) != 180 sizeof(vmst->hdr)) { 181 _fvc_err(kd, kd->program, "cannot read dump header"); 182 return (-1); 183diff --git a/lib/fvc_private.c b/lib/fvc_private.c 184index 0069a54..fc798fe 100644 185--- a/lib/fvc_private.c 186+++ b/lib/fvc_private.c 187@@ -130,7 +130,7 @@ _fvc_is_minidump(fvc_t *kd) 188 { 189 char minihdr[8]; 190 191- if (pread(kd->pmfd, &minihdr, 8, 0) == 8 && 192+ if (xpread(kd->pmfd, &minihdr, 8, 0) == 8 && 193 memcmp(&minihdr, "minidump", 8) == 0) 194 return (1); 195 return (0); 196@@ -256,6 +256,7 @@ _fvc_pmap_get(fvc_t *kd, u_long idx, size_t len) 197 198 if ((off_t)off >= kd->pt_sparse_off) 199 return (NULL); 200+ printf("%% RD: %zu %zu\n", kd->page_map_off+off, len); 201 return (void *)((uintptr_t)kd->page_map + off); 202 } 203 204@@ -270,8 +271,13 @@ _fvc_map_get(fvc_t *kd, u_long pa, unsigned int page_size) 205 return NULL; 206 207 addr = (uintptr_t)kd->page_map + off; 208- if (off >= kd->pt_sparse_off) 209+ if (off >= kd->pt_sparse_off) { 210+ 211 addr = (uintptr_t)kd->sparse_map + (off - kd->pt_sparse_off); 212+ printf("%% RD: %zu %u\n", off, page_size); 213+ } 214+ else 215+ printf("%% RD: %zu %u\n", kd->page_map_off+off, page_size); 216 return (void *)addr; 217 } 218 219@@ -289,6 +295,7 @@ _fvc_pt_init(fvc_t *kd, size_t dump_avail_size, off_t dump_avail_off, 220 if (dump_avail_size > 0) { 221 kd->dump_avail = mmap(NULL, kd->dump_avail_size, PROT_READ, 222 MAP_PRIVATE, kd->pmfd, dump_avail_off); 223+ printf("%% RD: %zu %zu\n", dump_avail_off, dump_avail_size); 224 } else { 225 /* 226 * Older version minidumps don't provide dump_avail[], 227@@ -309,7 +316,7 @@ _fvc_pt_init(fvc_t *kd, size_t dump_avail_size, off_t dump_avail_off, 228 map_len); 229 return (-1); 230 } 231- rd = pread(kd->pmfd, kd->pt_map, map_len, map_off); 232+ rd = xpread(kd->pmfd, kd->pt_map, map_len, map_off); 233 if (rd < 0 || rd != (ssize_t)map_len) { 234 _fvc_err(kd, kd->program, "cannot read %zu bytes for bitmap", 235 map_len); 236diff --git a/man/fbsdvmcore.3 b/man/fbsdvmcore.3 237index 4285ba2..c0d760c 100644 238--- a/man/fbsdvmcore.3 239+++ b/man/fbsdvmcore.3 240@@ -89,4 +89,5 @@ etc. 241 .Xr fvc_geterr 3 , 242 .Xr fvc_kerndisp 3 , 243 .Xr fvc_open 3 , 244-.Xr fvc_read 3 245+.Xr fvc_read 3 , 246+.Xr fvc_write 3 247diff --git a/man/fvc_geterr.3 b/man/fvc_geterr.3 248index 964a097..7d74c25 100644 249--- a/man/fvc_geterr.3 250+++ b/man/fvc_geterr.3 251@@ -66,7 +66,8 @@ or an error has not been captured for 252 .Sh SEE ALSO 253 .Xr fvc 3 , 254 .Xr fvc_close 3 , 255-.Xr fvc_read 3 256+.Xr fvc_read 3 , 257+.Xr fvc_write 3 258 .Sh BUGS 259 This routine cannot be used to access error conditions due to a failed 260 .Fn fvc_open 261diff --git a/man/fvc_open.3 b/man/fvc_open.3 262index 1f8e3be..4ea93ed 100644 263--- a/man/fvc_open.3 264+++ b/man/fvc_open.3 265@@ -166,5 +166,6 @@ was 266 .Xr fvc_geterr 3 , 267 .Xr fvc_native 3 , 268 .Xr fvc_read 3 , 269+.Xr fvc_write 3 , 270 .Xr kmem 4 , 271 .Xr mem 4 272diff --git a/man/fvc_read.3 b/man/fvc_read.3 273index 7413d59..c18dadc 100644 274--- a/man/fvc_read.3 275+++ b/man/fvc_read.3 276@@ -36,18 +36,24 @@ 277 .Dt FVC_READ 3 278 .Os 279 .Sh NAME 280-.Nm fvc_read 281-.Nd read kernel virtual memory 282+.Nm fvc_read , 283+.Nm fvc_write 284+.Nd read or write kernel virtual memory 285 .Sh LIBRARY 286 .Lb libfbsdvmcore 287 .Sh SYNOPSIS 288 .In fvc.h 289 .Ft ssize_t 290 .Fn fvc_read "fvc_t *kd" "kvaddr_t addr" "void *buf" "size_t nbytes" 291+.Ft ssize_t 292+.Fn fvc_write "fvc_t *kd" "kvaddr_t addr" "void *buf" "size_t nbytes" 293 .Sh DESCRIPTION 294 The 295 .Fn fvc_read 296 function is used to read a crash dump file. 297+.Fn fvc_write 298+function is used to overwrite parts of a crash dump file. 299+Note that only the fragments already present can be written. 300 See 301 .Fn fvc_open 3 302 for information regarding opening kernel crash dumps. 303@@ -63,6 +69,13 @@ to 304 .Fa buf . 305 .Pp 306 The 307+.Fn fvc_write 308+function transfers 309+.Fa nbytes 310+bytes of data from 311+.Fa buf 312+to the kernel space address 313+.Fa addr . 314 .Sh RETURN VALUES 315 Upon success, the number of bytes actually transferred is returned. 316 Otherwise, -1 is returned. 317diff --git a/man/fvc_write.3 b/man/fvc_write.3 318new file mode 100644 319index 0000000..f25fc74 320--- /dev/null 321+++ b/man/fvc_write.3 322@@ -0,0 +1 @@ 323+.so man3/fvc_read.3 324