1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
|
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
|