| @@ -1,912 +1,917 @@ | | | @@ -1,912 +1,917 @@ |
1 | /* $NetBSD: kvm.c,v 1.104 2018/11/05 00:43:30 mrg Exp $ */ | | 1 | /* $NetBSD: kvm.c,v 1.105 2020/03/08 00:06:42 chs Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 1989, 1992, 1993 | | 4 | * Copyright (c) 1989, 1992, 1993 |
5 | * The Regents of the University of California. All rights reserved. | | 5 | * The Regents of the University of California. All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software developed by the Computer Systems | | 7 | * This code is derived from software developed by the Computer Systems |
8 | * Engineering group at Lawrence Berkeley Laboratory under DARPA contract | | 8 | * Engineering group at Lawrence Berkeley Laboratory under DARPA contract |
9 | * BG 91-66 and contributed to Berkeley. | | 9 | * BG 91-66 and contributed to Berkeley. |
10 | * | | 10 | * |
11 | * Redistribution and use in source and binary forms, with or without | | 11 | * Redistribution and use in source and binary forms, with or without |
12 | * modification, are permitted provided that the following conditions | | 12 | * modification, are permitted provided that the following conditions |
13 | * are met: | | 13 | * are met: |
14 | * 1. Redistributions of source code must retain the above copyright | | 14 | * 1. Redistributions of source code must retain the above copyright |
15 | * notice, this list of conditions and the following disclaimer. | | 15 | * notice, this list of conditions and the following disclaimer. |
16 | * 2. Redistributions in binary form must reproduce the above copyright | | 16 | * 2. Redistributions in binary form must reproduce the above copyright |
17 | * notice, this list of conditions and the following disclaimer in the | | 17 | * notice, this list of conditions and the following disclaimer in the |
18 | * documentation and/or other materials provided with the distribution. | | 18 | * documentation and/or other materials provided with the distribution. |
19 | * 3. Neither the name of the University nor the names of its contributors | | 19 | * 3. Neither the name of the University nor the names of its contributors |
20 | * may be used to endorse or promote products derived from this software | | 20 | * may be used to endorse or promote products derived from this software |
21 | * without specific prior written permission. | | 21 | * without specific prior written permission. |
22 | * | | 22 | * |
23 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | | 23 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
29 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 29 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
30 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 30 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
31 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 31 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
32 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 32 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
33 | * SUCH DAMAGE. | | 33 | * SUCH DAMAGE. |
34 | */ | | 34 | */ |
35 | | | 35 | |
36 | #include <sys/cdefs.h> | | 36 | #include <sys/cdefs.h> |
37 | #if defined(LIBC_SCCS) && !defined(lint) | | 37 | #if defined(LIBC_SCCS) && !defined(lint) |
38 | #if 0 | | 38 | #if 0 |
39 | static char sccsid[] = "@(#)kvm.c 8.2 (Berkeley) 2/13/94"; | | 39 | static char sccsid[] = "@(#)kvm.c 8.2 (Berkeley) 2/13/94"; |
40 | #else | | 40 | #else |
41 | __RCSID("$NetBSD: kvm.c,v 1.104 2018/11/05 00:43:30 mrg Exp $"); | | 41 | __RCSID("$NetBSD: kvm.c,v 1.105 2020/03/08 00:06:42 chs Exp $"); |
42 | #endif | | 42 | #endif |
43 | #endif /* LIBC_SCCS and not lint */ | | 43 | #endif /* LIBC_SCCS and not lint */ |
44 | | | 44 | |
45 | #include <sys/param.h> | | 45 | #include <sys/param.h> |
46 | #include <sys/lwp.h> | | 46 | #include <sys/lwp.h> |
47 | #include <sys/proc.h> | | 47 | #include <sys/proc.h> |
48 | #include <sys/ioctl.h> | | 48 | #include <sys/ioctl.h> |
49 | #include <sys/stat.h> | | 49 | #include <sys/stat.h> |
50 | #include <sys/sysctl.h> | | 50 | #include <sys/sysctl.h> |
51 | | | 51 | |
52 | #include <sys/core.h> | | 52 | #include <sys/core.h> |
53 | #include <sys/exec.h> | | 53 | #include <sys/exec.h> |
54 | #include <sys/kcore.h> | | 54 | #include <sys/kcore.h> |
55 | #include <sys/ksyms.h> | | 55 | #include <sys/ksyms.h> |
56 | #include <sys/types.h> | | 56 | #include <sys/types.h> |
57 | | | 57 | |
58 | #include <uvm/uvm_extern.h> | | 58 | #include <uvm/uvm_extern.h> |
59 | | | 59 | |
60 | #include <machine/cpu.h> | | 60 | #include <machine/cpu.h> |
61 | | | 61 | |
62 | #include <ctype.h> | | 62 | #include <ctype.h> |
63 | #include <errno.h> | | 63 | #include <errno.h> |
64 | #include <fcntl.h> | | 64 | #include <fcntl.h> |
65 | #include <limits.h> | | 65 | #include <limits.h> |
66 | #include <nlist.h> | | 66 | #include <nlist.h> |
67 | #include <paths.h> | | 67 | #include <paths.h> |
68 | #include <stdarg.h> | | 68 | #include <stdarg.h> |
69 | #include <stdio.h> | | 69 | #include <stdio.h> |
70 | #include <stdlib.h> | | 70 | #include <stdlib.h> |
71 | #include <string.h> | | 71 | #include <string.h> |
72 | #include <unistd.h> | | 72 | #include <unistd.h> |
73 | #include <kvm.h> | | 73 | #include <kvm.h> |
74 | | | 74 | |
75 | #include "kvm_private.h" | | 75 | #include "kvm_private.h" |
76 | | | 76 | |
77 | static int _kvm_get_header(kvm_t *); | | 77 | static int _kvm_get_header(kvm_t *); |
78 | static kvm_t *_kvm_open(kvm_t *, const char *, const char *, | | 78 | static kvm_t *_kvm_open(kvm_t *, const char *, const char *, |
79 | const char *, int, char *); | | 79 | const char *, int, char *); |
80 | static int clear_gap(kvm_t *, bool (*)(void *, const void *, size_t), | | 80 | static int clear_gap(kvm_t *, bool (*)(void *, const void *, size_t), |
81 | void *, size_t); | | 81 | void *, size_t); |
82 | static off_t Lseek(kvm_t *, int, off_t, int); | | 82 | static off_t Lseek(kvm_t *, int, off_t, int); |
83 | static ssize_t Pread(kvm_t *, int, void *, size_t, off_t); | | 83 | static ssize_t Pread(kvm_t *, int, void *, size_t, off_t); |
84 | | | 84 | |
85 | char * | | 85 | char * |
86 | kvm_geterr(kvm_t *kd) | | 86 | kvm_geterr(kvm_t *kd) |
87 | { | | 87 | { |
88 | return (kd->errbuf); | | 88 | return (kd->errbuf); |
89 | } | | 89 | } |
90 | | | 90 | |
91 | const char * | | 91 | const char * |
92 | kvm_getkernelname(kvm_t *kd) | | 92 | kvm_getkernelname(kvm_t *kd) |
93 | { | | 93 | { |
94 | return kd->kernelname; | | 94 | return kd->kernelname; |
95 | } | | 95 | } |
96 | | | 96 | |
97 | /* | | 97 | /* |
98 | * Report an error using printf style arguments. "program" is kd->program | | 98 | * Report an error using printf style arguments. "program" is kd->program |
99 | * on hard errors, and 0 on soft errors, so that under sun error emulation, | | 99 | * on hard errors, and 0 on soft errors, so that under sun error emulation, |
100 | * only hard errors are printed out (otherwise, programs like gdb will | | 100 | * only hard errors are printed out (otherwise, programs like gdb will |
101 | * generate tons of error messages when trying to access bogus pointers). | | 101 | * generate tons of error messages when trying to access bogus pointers). |
102 | */ | | 102 | */ |
103 | void | | 103 | void |
104 | _kvm_err(kvm_t *kd, const char *program, const char *fmt, ...) | | 104 | _kvm_err(kvm_t *kd, const char *program, const char *fmt, ...) |
105 | { | | 105 | { |
106 | va_list ap; | | 106 | va_list ap; |
107 | | | 107 | |
108 | va_start(ap, fmt); | | 108 | va_start(ap, fmt); |
109 | if (program != NULL) { | | 109 | if (program != NULL) { |
110 | (void)fprintf(stderr, "%s: ", program); | | 110 | (void)fprintf(stderr, "%s: ", program); |
111 | (void)vfprintf(stderr, fmt, ap); | | 111 | (void)vfprintf(stderr, fmt, ap); |
112 | (void)fputc('\n', stderr); | | 112 | (void)fputc('\n', stderr); |
113 | } else | | 113 | } else |
114 | (void)vsnprintf(kd->errbuf, | | 114 | (void)vsnprintf(kd->errbuf, |
115 | sizeof(kd->errbuf), fmt, ap); | | 115 | sizeof(kd->errbuf), fmt, ap); |
116 | | | 116 | |
117 | va_end(ap); | | 117 | va_end(ap); |
118 | } | | 118 | } |
119 | | | 119 | |
120 | void | | 120 | void |
121 | _kvm_syserr(kvm_t *kd, const char *program, const char *fmt, ...) | | 121 | _kvm_syserr(kvm_t *kd, const char *program, const char *fmt, ...) |
122 | { | | 122 | { |
123 | va_list ap; | | 123 | va_list ap; |
124 | size_t n; | | 124 | size_t n; |
125 | | | 125 | |
126 | va_start(ap, fmt); | | 126 | va_start(ap, fmt); |
127 | if (program != NULL) { | | 127 | if (program != NULL) { |
128 | (void)fprintf(stderr, "%s: ", program); | | 128 | (void)fprintf(stderr, "%s: ", program); |
129 | (void)vfprintf(stderr, fmt, ap); | | 129 | (void)vfprintf(stderr, fmt, ap); |
130 | (void)fprintf(stderr, ": %s\n", strerror(errno)); | | 130 | (void)fprintf(stderr, ": %s\n", strerror(errno)); |
131 | } else { | | 131 | } else { |
132 | char *cp = kd->errbuf; | | 132 | char *cp = kd->errbuf; |
133 | | | 133 | |
134 | (void)vsnprintf(cp, sizeof(kd->errbuf), fmt, ap); | | 134 | (void)vsnprintf(cp, sizeof(kd->errbuf), fmt, ap); |
135 | n = strlen(cp); | | 135 | n = strlen(cp); |
136 | (void)snprintf(&cp[n], sizeof(kd->errbuf) - n, ": %s", | | 136 | (void)snprintf(&cp[n], sizeof(kd->errbuf) - n, ": %s", |
137 | strerror(errno)); | | 137 | strerror(errno)); |
138 | } | | 138 | } |
139 | va_end(ap); | | 139 | va_end(ap); |
140 | } | | 140 | } |
141 | | | 141 | |
142 | void * | | 142 | void * |
143 | _kvm_malloc(kvm_t *kd, size_t n) | | 143 | _kvm_malloc(kvm_t *kd, size_t n) |
144 | { | | 144 | { |
145 | void *p; | | 145 | void *p; |
146 | | | 146 | |
147 | if ((p = malloc(n)) == NULL) | | 147 | if ((p = malloc(n)) == NULL) |
148 | _kvm_err(kd, kd->program, "%s", strerror(errno)); | | 148 | _kvm_err(kd, kd->program, "%s", strerror(errno)); |
149 | return (p); | | 149 | return (p); |
150 | } | | 150 | } |
151 | | | 151 | |
152 | /* | | 152 | /* |
153 | * Wrapper around the lseek(2) system call; calls _kvm_syserr() for us | | 153 | * Wrapper around the lseek(2) system call; calls _kvm_syserr() for us |
154 | * in the event of emergency. | | 154 | * in the event of emergency. |
155 | */ | | 155 | */ |
156 | static off_t | | 156 | static off_t |
157 | Lseek(kvm_t *kd, int fd, off_t offset, int whence) | | 157 | Lseek(kvm_t *kd, int fd, off_t offset, int whence) |
158 | { | | 158 | { |
159 | off_t off; | | 159 | off_t off; |
160 | | | 160 | |
161 | errno = 0; | | 161 | errno = 0; |
162 | | | 162 | |
163 | if ((off = lseek(fd, offset, whence)) == -1 && errno != 0) { | | 163 | if ((off = lseek(fd, offset, whence)) == -1 && errno != 0) { |
164 | _kvm_syserr(kd, kd->program, "Lseek"); | | 164 | _kvm_syserr(kd, kd->program, "Lseek"); |
165 | return ((off_t)-1); | | 165 | return ((off_t)-1); |
166 | } | | 166 | } |
167 | return (off); | | 167 | return (off); |
168 | } | | 168 | } |
169 | | | 169 | |
170 | ssize_t | | 170 | ssize_t |
171 | _kvm_pread(kvm_t *kd, int fd, void *buf, size_t size, off_t off) | | 171 | _kvm_pread(kvm_t *kd, int fd, void *buf, size_t size, off_t off) |
172 | { | | 172 | { |
173 | ptrdiff_t moff; | | 173 | ptrdiff_t moff; |
174 | void *newbuf; | | 174 | void *newbuf; |
175 | size_t dsize; | | 175 | size_t dsize; |
176 | ssize_t rv; | | 176 | ssize_t rv; |
177 | off_t doff; | | 177 | off_t doff; |
178 | | | 178 | |
179 | /* If aligned nothing to do. */ | | 179 | /* If aligned nothing to do. */ |
180 | if (((off % kd->fdalign) | (size % kd->fdalign)) == 0) { | | 180 | if (((off % kd->fdalign) | (size % kd->fdalign)) == 0) { |
181 | return pread(fd, buf, size, off); | | 181 | return pread(fd, buf, size, off); |
182 | } | | 182 | } |
183 | | | 183 | |
184 | /* | | 184 | /* |
185 | * Otherwise must buffer. We can't tolerate short reads in this | | 185 | * Otherwise must buffer. We can't tolerate short reads in this |
186 | * case (lazy bum). | | 186 | * case (lazy bum). |
187 | */ | | 187 | */ |
188 | moff = (ptrdiff_t)off % kd->fdalign; | | 188 | moff = (ptrdiff_t)off % kd->fdalign; |
189 | doff = off - moff; | | 189 | doff = off - moff; |
190 | dsize = moff + size + kd->fdalign - 1; | | 190 | dsize = moff + size + kd->fdalign - 1; |
191 | dsize -= dsize % kd->fdalign; | | 191 | dsize -= dsize % kd->fdalign; |
192 | if (kd->iobufsz < dsize) { | | 192 | if (kd->iobufsz < dsize) { |
193 | newbuf = realloc(kd->iobuf, dsize); | | 193 | newbuf = realloc(kd->iobuf, dsize); |
194 | if (newbuf == NULL) { | | 194 | if (newbuf == NULL) { |
195 | _kvm_syserr(kd, 0, "cannot allocate I/O buffer"); | | 195 | _kvm_syserr(kd, 0, "cannot allocate I/O buffer"); |
196 | return (-1); | | 196 | return (-1); |
197 | } | | 197 | } |
198 | kd->iobuf = newbuf; | | 198 | kd->iobuf = newbuf; |
199 | kd->iobufsz = dsize; | | 199 | kd->iobufsz = dsize; |
200 | } | | 200 | } |
201 | rv = pread(fd, kd->iobuf, dsize, doff); | | 201 | rv = pread(fd, kd->iobuf, dsize, doff); |
202 | if (rv < size + moff) | | 202 | if (rv < size + moff) |
203 | return -1; | | 203 | return -1; |
204 | memcpy(buf, kd->iobuf + moff, size); | | 204 | memcpy(buf, kd->iobuf + moff, size); |
205 | return size; | | 205 | return size; |
206 | } | | 206 | } |
207 | | | 207 | |
208 | /* | | 208 | /* |
209 | * Wrapper around the pread(2) system call; calls _kvm_syserr() for us | | 209 | * Wrapper around the pread(2) system call; calls _kvm_syserr() for us |
210 | * in the event of emergency. | | 210 | * in the event of emergency. |
211 | */ | | 211 | */ |
212 | static ssize_t | | 212 | static ssize_t |
213 | Pread(kvm_t *kd, int fd, void *buf, size_t nbytes, off_t offset) | | 213 | Pread(kvm_t *kd, int fd, void *buf, size_t nbytes, off_t offset) |
214 | { | | 214 | { |
215 | ssize_t rv; | | 215 | ssize_t rv; |
216 | | | 216 | |
217 | errno = 0; | | 217 | errno = 0; |
218 | | | 218 | |
219 | if ((rv = _kvm_pread(kd, fd, buf, nbytes, offset)) != nbytes && | | 219 | if ((rv = _kvm_pread(kd, fd, buf, nbytes, offset)) != nbytes && |
220 | errno != 0) | | 220 | errno != 0) |
221 | _kvm_syserr(kd, kd->program, "Pread"); | | 221 | _kvm_syserr(kd, kd->program, "Pread"); |
222 | return (rv); | | 222 | return (rv); |
223 | } | | 223 | } |
224 | | | 224 | |
225 | static kvm_t * | | 225 | static kvm_t * |
226 | _kvm_open(kvm_t *kd, const char *uf, const char *mf, const char *sf, int flag, | | 226 | _kvm_open(kvm_t *kd, const char *uf, const char *mf, const char *sf, int flag, |
227 | char *errout) | | 227 | char *errout) |
228 | { | | 228 | { |
229 | struct stat st; | | 229 | struct stat st; |
230 | int ufgiven; | | 230 | int ufgiven; |
231 | | | 231 | |
232 | kd->pmfd = -1; | | 232 | kd->pmfd = -1; |
233 | kd->vmfd = -1; | | 233 | kd->vmfd = -1; |
234 | kd->swfd = -1; | | 234 | kd->swfd = -1; |
235 | kd->nlfd = -1; | | 235 | kd->nlfd = -1; |
236 | kd->alive = KVM_ALIVE_DEAD; | | 236 | kd->alive = KVM_ALIVE_DEAD; |
237 | kd->procbase = NULL; | | 237 | kd->procbase = NULL; |
238 | kd->procbase_len = 0; | | 238 | kd->procbase_len = 0; |
239 | kd->procbase2 = NULL; | | 239 | kd->procbase2 = NULL; |
240 | kd->procbase2_len = 0; | | 240 | kd->procbase2_len = 0; |
241 | kd->lwpbase = NULL; | | 241 | kd->lwpbase = NULL; |
242 | kd->lwpbase_len = 0; | | 242 | kd->lwpbase_len = 0; |
243 | kd->nbpg = getpagesize(); | | 243 | kd->nbpg = getpagesize(); |
244 | kd->swapspc = NULL; | | 244 | kd->swapspc = NULL; |
245 | kd->argspc = NULL; | | 245 | kd->argspc = NULL; |
246 | kd->argspc_len = 0; | | 246 | kd->argspc_len = 0; |
247 | kd->argbuf = NULL; | | 247 | kd->argbuf = NULL; |
248 | kd->argv = NULL; | | 248 | kd->argv = NULL; |
249 | kd->vmst = NULL; | | 249 | kd->vmst = NULL; |
250 | kd->vm_page_buckets = NULL; | | 250 | kd->vm_page_buckets = NULL; |
251 | kd->kcore_hdr = NULL; | | 251 | kd->kcore_hdr = NULL; |
252 | kd->cpu_dsize = 0; | | 252 | kd->cpu_dsize = 0; |
253 | kd->cpu_data = NULL; | | 253 | kd->cpu_data = NULL; |
254 | kd->dump_off = 0; | | 254 | kd->dump_off = 0; |
255 | kd->fdalign = 1; | | 255 | kd->fdalign = 1; |
256 | kd->iobuf = NULL; | | 256 | kd->iobuf = NULL; |
257 | kd->iobufsz = 0; | | 257 | kd->iobufsz = 0; |
258 | kd->errbuf[0] = '\0'; | | 258 | kd->errbuf[0] = '\0'; |
259 | | | 259 | |
260 | if (flag & KVM_NO_FILES) { | | 260 | if (flag & KVM_NO_FILES) { |
261 | kd->alive = KVM_ALIVE_SYSCTL; | | 261 | kd->alive = KVM_ALIVE_SYSCTL; |
262 | return(kd); | | 262 | return(kd); |
263 | } | | 263 | } |
264 | | | 264 | |
265 | /* | | 265 | /* |
266 | * Call the MD open hook. This sets: | | 266 | * Call the MD open hook. This sets: |
267 | * usrstack, min_uva, max_uva | | 267 | * usrstack, min_uva, max_uva |
268 | */ | | 268 | */ |
269 | if (_kvm_mdopen(kd)) { | | 269 | if (_kvm_mdopen(kd)) { |
270 | _kvm_err(kd, kd->program, "md init failed"); | | 270 | _kvm_err(kd, kd->program, "md init failed"); |
271 | goto failed; | | 271 | goto failed; |
272 | } | | 272 | } |
273 | | | 273 | |
274 | ufgiven = (uf != NULL); | | 274 | ufgiven = (uf != NULL); |
275 | if (!ufgiven) { | | 275 | if (!ufgiven) { |
276 | #ifdef CPU_BOOTED_KERNEL | | 276 | #ifdef CPU_BOOTED_KERNEL |
277 | /* 130 is 128 + '/' + '\0' */ | | 277 | /* 130 is 128 + '/' + '\0' */ |
278 | static char booted_kernel[130]; | | 278 | static char booted_kernel[130]; |
279 | int mib[2], rc; | | 279 | int mib[2], rc; |
280 | size_t len; | | 280 | size_t len; |
281 | | | 281 | |
282 | mib[0] = CTL_MACHDEP; | | 282 | mib[0] = CTL_MACHDEP; |
283 | mib[1] = CPU_BOOTED_KERNEL; | | 283 | mib[1] = CPU_BOOTED_KERNEL; |
284 | booted_kernel[0] = '/'; | | 284 | booted_kernel[0] = '/'; |
285 | booted_kernel[1] = '\0'; | | 285 | booted_kernel[1] = '\0'; |
286 | len = sizeof(booted_kernel) - 2; | | 286 | len = sizeof(booted_kernel) - 2; |
287 | rc = sysctl(&mib[0], 2, &booted_kernel[1], &len, NULL, 0); | | 287 | rc = sysctl(&mib[0], 2, &booted_kernel[1], &len, NULL, 0); |
288 | booted_kernel[sizeof(booted_kernel) - 1] = '\0'; | | 288 | booted_kernel[sizeof(booted_kernel) - 1] = '\0'; |
289 | uf = (booted_kernel[1] == '/') ? | | 289 | uf = (booted_kernel[1] == '/') ? |
290 | &booted_kernel[1] : &booted_kernel[0]; | | 290 | &booted_kernel[1] : &booted_kernel[0]; |
291 | if (rc != -1) | | 291 | if (rc != -1) |
292 | rc = stat(uf, &st); | | 292 | rc = stat(uf, &st); |
293 | if (rc != -1 && !S_ISREG(st.st_mode)) | | 293 | if (rc != -1 && !S_ISREG(st.st_mode)) |
294 | rc = -1; | | 294 | rc = -1; |
295 | if (rc == -1) | | 295 | if (rc == -1) |
296 | #endif /* CPU_BOOTED_KERNEL */ | | 296 | #endif /* CPU_BOOTED_KERNEL */ |
297 | uf = _PATH_UNIX; | | 297 | uf = _PATH_UNIX; |
298 | } | | 298 | } |
299 | else if (strlen(uf) >= MAXPATHLEN) { | | 299 | else if (strlen(uf) >= MAXPATHLEN) { |
300 | _kvm_err(kd, kd->program, "exec file name too long"); | | 300 | _kvm_err(kd, kd->program, "exec file name too long"); |
301 | goto failed; | | 301 | goto failed; |
302 | } | | 302 | } |
303 | if (flag & ~O_RDWR) { | | 303 | if (flag & ~O_RDWR) { |
304 | _kvm_err(kd, kd->program, "bad flags arg"); | | 304 | _kvm_err(kd, kd->program, "bad flags arg"); |
305 | goto failed; | | 305 | goto failed; |
306 | } | | 306 | } |
307 | if (mf == 0) | | 307 | if (mf == 0) |
308 | mf = _PATH_MEM; | | 308 | mf = _PATH_MEM; |
309 | if (sf == 0) | | 309 | if (sf == 0) |
310 | sf = _PATH_DRUM; | | 310 | sf = _PATH_DRUM; |
311 | | | 311 | |
312 | /* | | 312 | /* |
313 | * Open the kernel namelist. If /dev/ksyms doesn't | | 313 | * Open the kernel namelist. If /dev/ksyms doesn't |
314 | * exist, open the current kernel. | | 314 | * exist, open the current kernel. |
315 | */ | | 315 | */ |
316 | if (ufgiven == 0) | | 316 | if (ufgiven == 0) |
317 | kd->nlfd = open(_PATH_KSYMS, O_RDONLY | O_CLOEXEC, 0); | | 317 | kd->nlfd = open(_PATH_KSYMS, O_RDONLY | O_CLOEXEC, 0); |
318 | if (kd->nlfd < 0) { | | 318 | if (kd->nlfd < 0) { |
319 | if ((kd->nlfd = open(uf, O_RDONLY | O_CLOEXEC, 0)) < 0) { | | 319 | if ((kd->nlfd = open(uf, O_RDONLY | O_CLOEXEC, 0)) < 0) { |
320 | _kvm_syserr(kd, kd->program, "%s", uf); | | 320 | _kvm_syserr(kd, kd->program, "%s", uf); |
321 | goto failed; | | 321 | goto failed; |
322 | } | | 322 | } |
323 | strlcpy(kd->kernelname, uf, sizeof(kd->kernelname)); | | 323 | strlcpy(kd->kernelname, uf, sizeof(kd->kernelname)); |
324 | } else { | | 324 | } else { |
325 | strlcpy(kd->kernelname, _PATH_KSYMS, sizeof(kd->kernelname)); | | 325 | strlcpy(kd->kernelname, _PATH_KSYMS, sizeof(kd->kernelname)); |
326 | } | | 326 | } |
327 | | | 327 | |
328 | if ((kd->pmfd = open(mf, flag | O_CLOEXEC, 0)) < 0) { | | 328 | if ((kd->pmfd = open(mf, flag | O_CLOEXEC, 0)) < 0) { |
329 | _kvm_syserr(kd, kd->program, "%s", mf); | | 329 | _kvm_syserr(kd, kd->program, "%s", mf); |
330 | goto failed; | | 330 | goto failed; |
331 | } | | 331 | } |
332 | if (fstat(kd->pmfd, &st) < 0) { | | 332 | if (fstat(kd->pmfd, &st) < 0) { |
333 | _kvm_syserr(kd, kd->program, "%s", mf); | | 333 | _kvm_syserr(kd, kd->program, "%s", mf); |
334 | goto failed; | | 334 | goto failed; |
335 | } | | 335 | } |
336 | if (S_ISCHR(st.st_mode) && strcmp(mf, _PATH_MEM) == 0) { | | 336 | if (S_ISCHR(st.st_mode) && strcmp(mf, _PATH_MEM) == 0) { |
337 | /* | | 337 | /* |
338 | * If this is /dev/mem, open kmem too. (Maybe we should | | 338 | * If this is /dev/mem, open kmem too. (Maybe we should |
339 | * make it work for either /dev/mem or /dev/kmem -- in either | | 339 | * make it work for either /dev/mem or /dev/kmem -- in either |
340 | * case you're working with a live kernel.) | | 340 | * case you're working with a live kernel.) |
341 | */ | | 341 | */ |
342 | if ((kd->vmfd = open(_PATH_KMEM, flag | O_CLOEXEC, 0)) < 0) { | | 342 | if ((kd->vmfd = open(_PATH_KMEM, flag | O_CLOEXEC, 0)) < 0) { |
343 | _kvm_syserr(kd, kd->program, "%s", _PATH_KMEM); | | 343 | _kvm_syserr(kd, kd->program, "%s", _PATH_KMEM); |
344 | goto failed; | | 344 | goto failed; |
345 | } | | 345 | } |
346 | kd->alive = KVM_ALIVE_FILES; | | 346 | kd->alive = KVM_ALIVE_FILES; |
347 | if ((kd->swfd = open(sf, flag | O_CLOEXEC, 0)) < 0) { | | 347 | if ((kd->swfd = open(sf, flag | O_CLOEXEC, 0)) < 0) { |
348 | if (errno != ENXIO) { | | 348 | if (errno != ENXIO) { |
349 | _kvm_syserr(kd, kd->program, "%s", sf); | | 349 | _kvm_syserr(kd, kd->program, "%s", sf); |
350 | goto failed; | | 350 | goto failed; |
351 | } | | 351 | } |
352 | /* swap is not configured? not fatal */ | | 352 | /* swap is not configured? not fatal */ |
353 | } | | 353 | } |
354 | } else { | | 354 | } else { |
355 | kd->fdalign = DEV_BSIZE; /* XXX */ | | 355 | if (S_ISCHR(st.st_mode)) { |
| | | 356 | kd->fdalign = DEV_BSIZE; |
| | | 357 | } else { |
| | | 358 | kd->fdalign = 1; |
| | | 359 | } |
| | | 360 | |
356 | /* | | 361 | /* |
357 | * This is a crash dump. | | 362 | * This is a crash dump. |
358 | * Initialize the virtual address translation machinery. | | 363 | * Initialize the virtual address translation machinery. |
359 | * | | 364 | * |
360 | * If there is no valid core header, fail silently here. | | 365 | * If there is no valid core header, fail silently here. |
361 | * The address translations however will fail without | | 366 | * The address translations however will fail without |
362 | * header. Things can be made to run by calling | | 367 | * header. Things can be made to run by calling |
363 | * kvm_dump_mkheader() before doing any translation. | | 368 | * kvm_dump_mkheader() before doing any translation. |
364 | */ | | 369 | */ |
365 | if (_kvm_get_header(kd) == 0) { | | 370 | if (_kvm_get_header(kd) == 0) { |
366 | if (_kvm_initvtop(kd) < 0) | | 371 | if (_kvm_initvtop(kd) < 0) |
367 | goto failed; | | 372 | goto failed; |
368 | } | | 373 | } |
369 | } | | 374 | } |
370 | return (kd); | | 375 | return (kd); |
371 | failed: | | 376 | failed: |
372 | /* | | 377 | /* |
373 | * Copy out the error if doing sane error semantics. | | 378 | * Copy out the error if doing sane error semantics. |
374 | */ | | 379 | */ |
375 | if (errout != 0) | | 380 | if (errout != 0) |
376 | (void)strlcpy(errout, kd->errbuf, _POSIX2_LINE_MAX); | | 381 | (void)strlcpy(errout, kd->errbuf, _POSIX2_LINE_MAX); |
377 | (void)kvm_close(kd); | | 382 | (void)kvm_close(kd); |
378 | return (0); | | 383 | return (0); |
379 | } | | 384 | } |
380 | | | 385 | |
381 | /* | | 386 | /* |
382 | * The kernel dump file (from savecore) contains: | | 387 | * The kernel dump file (from savecore) contains: |
383 | * kcore_hdr_t kcore_hdr; | | 388 | * kcore_hdr_t kcore_hdr; |
384 | * kcore_seg_t cpu_hdr; | | 389 | * kcore_seg_t cpu_hdr; |
385 | * (opaque) cpu_data; (size is cpu_hdr.c_size) | | 390 | * (opaque) cpu_data; (size is cpu_hdr.c_size) |
386 | * kcore_seg_t mem_hdr; | | 391 | * kcore_seg_t mem_hdr; |
387 | * (memory) mem_data; (size is mem_hdr.c_size) | | 392 | * (memory) mem_data; (size is mem_hdr.c_size) |
388 | * | | 393 | * |
389 | * Note: khdr is padded to khdr.c_hdrsize; | | 394 | * Note: khdr is padded to khdr.c_hdrsize; |
390 | * cpu_hdr and mem_hdr are padded to khdr.c_seghdrsize | | 395 | * cpu_hdr and mem_hdr are padded to khdr.c_seghdrsize |
391 | */ | | 396 | */ |
392 | static int | | 397 | static int |
393 | _kvm_get_header(kvm_t *kd) | | 398 | _kvm_get_header(kvm_t *kd) |
394 | { | | 399 | { |
395 | kcore_hdr_t kcore_hdr; | | 400 | kcore_hdr_t kcore_hdr; |
396 | kcore_seg_t cpu_hdr; | | 401 | kcore_seg_t cpu_hdr; |
397 | kcore_seg_t mem_hdr; | | 402 | kcore_seg_t mem_hdr; |
398 | size_t offset; | | 403 | size_t offset; |
399 | ssize_t sz; | | 404 | ssize_t sz; |
400 | | | 405 | |
401 | /* | | 406 | /* |
402 | * Read the kcore_hdr_t | | 407 | * Read the kcore_hdr_t |
403 | */ | | 408 | */ |
404 | sz = Pread(kd, kd->pmfd, &kcore_hdr, sizeof(kcore_hdr), (off_t)0); | | 409 | sz = Pread(kd, kd->pmfd, &kcore_hdr, sizeof(kcore_hdr), (off_t)0); |
405 | if (sz != sizeof(kcore_hdr)) | | 410 | if (sz != sizeof(kcore_hdr)) |
406 | return (-1); | | 411 | return (-1); |
407 | | | 412 | |
408 | /* | | 413 | /* |
409 | * Currently, we only support dump-files made by the current | | 414 | * Currently, we only support dump-files made by the current |
410 | * architecture... | | 415 | * architecture... |
411 | */ | | 416 | */ |
412 | if ((CORE_GETMAGIC(kcore_hdr) != KCORE_MAGIC) || | | 417 | if ((CORE_GETMAGIC(kcore_hdr) != KCORE_MAGIC) || |
413 | (CORE_GETMID(kcore_hdr) != MID_MACHINE)) | | 418 | (CORE_GETMID(kcore_hdr) != MID_MACHINE)) |
414 | return (-1); | | 419 | return (-1); |
415 | | | 420 | |
416 | /* | | 421 | /* |
417 | * Currently, we only support exactly 2 segments: cpu-segment | | 422 | * Currently, we only support exactly 2 segments: cpu-segment |
418 | * and data-segment in exactly that order. | | 423 | * and data-segment in exactly that order. |
419 | */ | | 424 | */ |
420 | if (kcore_hdr.c_nseg != 2) | | 425 | if (kcore_hdr.c_nseg != 2) |
421 | return (-1); | | 426 | return (-1); |
422 | | | 427 | |
423 | /* | | 428 | /* |
424 | * Save away the kcore_hdr. All errors after this | | 429 | * Save away the kcore_hdr. All errors after this |
425 | * should do a to "goto fail" to deallocate things. | | 430 | * should do a to "goto fail" to deallocate things. |
426 | */ | | 431 | */ |
427 | kd->kcore_hdr = _kvm_malloc(kd, sizeof(kcore_hdr)); | | 432 | kd->kcore_hdr = _kvm_malloc(kd, sizeof(kcore_hdr)); |
428 | memcpy(kd->kcore_hdr, &kcore_hdr, sizeof(kcore_hdr)); | | 433 | memcpy(kd->kcore_hdr, &kcore_hdr, sizeof(kcore_hdr)); |
429 | offset = kcore_hdr.c_hdrsize; | | 434 | offset = kcore_hdr.c_hdrsize; |
430 | | | 435 | |
431 | /* | | 436 | /* |
432 | * Read the CPU segment header | | 437 | * Read the CPU segment header |
433 | */ | | 438 | */ |
434 | sz = Pread(kd, kd->pmfd, &cpu_hdr, sizeof(cpu_hdr), (off_t)offset); | | 439 | sz = Pread(kd, kd->pmfd, &cpu_hdr, sizeof(cpu_hdr), (off_t)offset); |
435 | if (sz != sizeof(cpu_hdr)) | | 440 | if (sz != sizeof(cpu_hdr)) |
436 | goto fail; | | 441 | goto fail; |
437 | if ((CORE_GETMAGIC(cpu_hdr) != KCORESEG_MAGIC) || | | 442 | if ((CORE_GETMAGIC(cpu_hdr) != KCORESEG_MAGIC) || |
438 | (CORE_GETFLAG(cpu_hdr) != CORE_CPU)) | | 443 | (CORE_GETFLAG(cpu_hdr) != CORE_CPU)) |
439 | goto fail; | | 444 | goto fail; |
440 | offset += kcore_hdr.c_seghdrsize; | | 445 | offset += kcore_hdr.c_seghdrsize; |
441 | | | 446 | |
442 | /* | | 447 | /* |
443 | * Read the CPU segment DATA. | | 448 | * Read the CPU segment DATA. |
444 | */ | | 449 | */ |
445 | kd->cpu_dsize = cpu_hdr.c_size; | | 450 | kd->cpu_dsize = cpu_hdr.c_size; |
446 | kd->cpu_data = _kvm_malloc(kd, cpu_hdr.c_size); | | 451 | kd->cpu_data = _kvm_malloc(kd, cpu_hdr.c_size); |
447 | if (kd->cpu_data == NULL) | | 452 | if (kd->cpu_data == NULL) |
448 | goto fail; | | 453 | goto fail; |
449 | sz = Pread(kd, kd->pmfd, kd->cpu_data, cpu_hdr.c_size, (off_t)offset); | | 454 | sz = Pread(kd, kd->pmfd, kd->cpu_data, cpu_hdr.c_size, (off_t)offset); |
450 | if (sz != cpu_hdr.c_size) | | 455 | if (sz != cpu_hdr.c_size) |
451 | goto fail; | | 456 | goto fail; |
452 | offset += cpu_hdr.c_size; | | 457 | offset += cpu_hdr.c_size; |
453 | | | 458 | |
454 | /* | | 459 | /* |
455 | * Read the next segment header: data segment | | 460 | * Read the next segment header: data segment |
456 | */ | | 461 | */ |
457 | sz = Pread(kd, kd->pmfd, &mem_hdr, sizeof(mem_hdr), (off_t)offset); | | 462 | sz = Pread(kd, kd->pmfd, &mem_hdr, sizeof(mem_hdr), (off_t)offset); |
458 | if (sz != sizeof(mem_hdr)) | | 463 | if (sz != sizeof(mem_hdr)) |
459 | goto fail; | | 464 | goto fail; |
460 | offset += kcore_hdr.c_seghdrsize; | | 465 | offset += kcore_hdr.c_seghdrsize; |
461 | | | 466 | |
462 | if ((CORE_GETMAGIC(mem_hdr) != KCORESEG_MAGIC) || | | 467 | if ((CORE_GETMAGIC(mem_hdr) != KCORESEG_MAGIC) || |
463 | (CORE_GETFLAG(mem_hdr) != CORE_DATA)) | | 468 | (CORE_GETFLAG(mem_hdr) != CORE_DATA)) |
464 | goto fail; | | 469 | goto fail; |
465 | | | 470 | |
466 | kd->dump_off = offset; | | 471 | kd->dump_off = offset; |
467 | return (0); | | 472 | return (0); |
468 | | | 473 | |
469 | fail: | | 474 | fail: |
470 | if (kd->kcore_hdr != NULL) { | | 475 | if (kd->kcore_hdr != NULL) { |
471 | free(kd->kcore_hdr); | | 476 | free(kd->kcore_hdr); |
472 | kd->kcore_hdr = NULL; | | 477 | kd->kcore_hdr = NULL; |
473 | } | | 478 | } |
474 | if (kd->cpu_data != NULL) { | | 479 | if (kd->cpu_data != NULL) { |
475 | free(kd->cpu_data); | | 480 | free(kd->cpu_data); |
476 | kd->cpu_data = NULL; | | 481 | kd->cpu_data = NULL; |
477 | kd->cpu_dsize = 0; | | 482 | kd->cpu_dsize = 0; |
478 | } | | 483 | } |
479 | return (-1); | | 484 | return (-1); |
480 | } | | 485 | } |
481 | | | 486 | |
482 | /* | | 487 | /* |
483 | * The format while on the dump device is: (new format) | | 488 | * The format while on the dump device is: (new format) |
484 | * kcore_seg_t cpu_hdr; | | 489 | * kcore_seg_t cpu_hdr; |
485 | * (opaque) cpu_data; (size is cpu_hdr.c_size) | | 490 | * (opaque) cpu_data; (size is cpu_hdr.c_size) |
486 | * kcore_seg_t mem_hdr; | | 491 | * kcore_seg_t mem_hdr; |
487 | * (memory) mem_data; (size is mem_hdr.c_size) | | 492 | * (memory) mem_data; (size is mem_hdr.c_size) |
488 | */ | | 493 | */ |
489 | int | | 494 | int |
490 | kvm_dump_mkheader(kvm_t *kd, off_t dump_off) | | 495 | kvm_dump_mkheader(kvm_t *kd, off_t dump_off) |
491 | { | | 496 | { |
492 | kcore_seg_t cpu_hdr; | | 497 | kcore_seg_t cpu_hdr; |
493 | size_t hdr_size; | | 498 | size_t hdr_size; |
494 | ssize_t sz; | | 499 | ssize_t sz; |
495 | | | 500 | |
496 | if (kd->kcore_hdr != NULL) { | | 501 | if (kd->kcore_hdr != NULL) { |
497 | _kvm_err(kd, kd->program, "already has a dump header"); | | 502 | _kvm_err(kd, kd->program, "already has a dump header"); |
498 | return (-1); | | 503 | return (-1); |
499 | } | | 504 | } |
500 | if (ISALIVE(kd)) { | | 505 | if (ISALIVE(kd)) { |
501 | _kvm_err(kd, kd->program, "don't use on live kernel"); | | 506 | _kvm_err(kd, kd->program, "don't use on live kernel"); |
502 | return (-1); | | 507 | return (-1); |
503 | } | | 508 | } |
504 | | | 509 | |
505 | /* | | 510 | /* |
506 | * Validate new format crash dump | | 511 | * Validate new format crash dump |
507 | */ | | 512 | */ |
508 | sz = Pread(kd, kd->pmfd, &cpu_hdr, sizeof(cpu_hdr), dump_off); | | 513 | sz = Pread(kd, kd->pmfd, &cpu_hdr, sizeof(cpu_hdr), dump_off); |
509 | if (sz != sizeof(cpu_hdr)) { | | 514 | if (sz != sizeof(cpu_hdr)) { |
510 | if (sz == -1) | | 515 | if (sz == -1) |
511 | _kvm_err(kd, 0, "read %zx bytes at offset %"PRIx64 | | 516 | _kvm_err(kd, 0, "read %zx bytes at offset %"PRIx64 |
512 | " for cpu_hdr failed: %s", sizeof(cpu_hdr), | | 517 | " for cpu_hdr failed: %s", sizeof(cpu_hdr), |
513 | dump_off, strerror(errno)); | | 518 | dump_off, strerror(errno)); |
514 | else | | 519 | else |
515 | _kvm_err(kd, 0, "read %zx bytes at offset %"PRIx64 | | 520 | _kvm_err(kd, 0, "read %zx bytes at offset %"PRIx64 |
516 | " for cpu_hdr instead of requested %zu", | | 521 | " for cpu_hdr instead of requested %zu", |
517 | sz, dump_off, sizeof(cpu_hdr)); | | 522 | sz, dump_off, sizeof(cpu_hdr)); |
518 | return (-1); | | 523 | return (-1); |
519 | } | | 524 | } |
520 | if ((CORE_GETMAGIC(cpu_hdr) != KCORE_MAGIC) | | 525 | if ((CORE_GETMAGIC(cpu_hdr) != KCORE_MAGIC) |
521 | || (CORE_GETMID(cpu_hdr) != MID_MACHINE)) { | | 526 | || (CORE_GETMID(cpu_hdr) != MID_MACHINE)) { |
522 | _kvm_err(kd, 0, "invalid magic in cpu_hdr"); | | 527 | _kvm_err(kd, 0, "invalid magic in cpu_hdr"); |
523 | return (0); | | 528 | return (0); |
524 | } | | 529 | } |
525 | hdr_size = ALIGN(sizeof(cpu_hdr)); | | 530 | hdr_size = ALIGN(sizeof(cpu_hdr)); |
526 | | | 531 | |
527 | /* | | 532 | /* |
528 | * Read the CPU segment. | | 533 | * Read the CPU segment. |
529 | */ | | 534 | */ |
530 | kd->cpu_dsize = cpu_hdr.c_size; | | 535 | kd->cpu_dsize = cpu_hdr.c_size; |
531 | kd->cpu_data = _kvm_malloc(kd, kd->cpu_dsize); | | 536 | kd->cpu_data = _kvm_malloc(kd, kd->cpu_dsize); |
532 | if (kd->cpu_data == NULL) { | | 537 | if (kd->cpu_data == NULL) { |
533 | _kvm_err(kd, kd->program, "no cpu_data"); | | 538 | _kvm_err(kd, kd->program, "no cpu_data"); |
534 | goto fail; | | 539 | goto fail; |
535 | } | | 540 | } |
536 | sz = Pread(kd, kd->pmfd, kd->cpu_data, cpu_hdr.c_size, | | 541 | sz = Pread(kd, kd->pmfd, kd->cpu_data, cpu_hdr.c_size, |
537 | dump_off + hdr_size); | | 542 | dump_off + hdr_size); |
538 | if (sz != cpu_hdr.c_size) { | | 543 | if (sz != cpu_hdr.c_size) { |
539 | _kvm_err(kd, kd->program, "size %zu != cpu_hdr.csize %"PRIu32, | | 544 | _kvm_err(kd, kd->program, "size %zu != cpu_hdr.csize %"PRIu32, |
540 | sz, cpu_hdr.c_size); | | 545 | sz, cpu_hdr.c_size); |
541 | goto fail; | | 546 | goto fail; |
542 | } | | 547 | } |
543 | hdr_size += kd->cpu_dsize; | | 548 | hdr_size += kd->cpu_dsize; |
544 | | | 549 | |
545 | /* | | 550 | /* |
546 | * Leave phys mem pointer at beginning of memory data | | 551 | * Leave phys mem pointer at beginning of memory data |
547 | */ | | 552 | */ |
548 | kd->dump_off = dump_off + hdr_size; | | 553 | kd->dump_off = dump_off + hdr_size; |
549 | if (Lseek(kd, kd->pmfd, kd->dump_off, SEEK_SET) == -1) { | | 554 | if (Lseek(kd, kd->pmfd, kd->dump_off, SEEK_SET) == -1) { |
550 | _kvm_err(kd, kd->program, "failed to seek to %" PRId64, | | 555 | _kvm_err(kd, kd->program, "failed to seek to %" PRId64, |
551 | (int64_t)kd->dump_off); | | 556 | (int64_t)kd->dump_off); |
552 | goto fail; | | 557 | goto fail; |
553 | } | | 558 | } |
554 | | | 559 | |
555 | /* | | 560 | /* |
556 | * Create a kcore_hdr. | | 561 | * Create a kcore_hdr. |
557 | */ | | 562 | */ |
558 | kd->kcore_hdr = _kvm_malloc(kd, sizeof(kcore_hdr_t)); | | 563 | kd->kcore_hdr = _kvm_malloc(kd, sizeof(kcore_hdr_t)); |
559 | if (kd->kcore_hdr == NULL) { | | 564 | if (kd->kcore_hdr == NULL) { |
560 | _kvm_err(kd, kd->program, "failed to allocate header"); | | 565 | _kvm_err(kd, kd->program, "failed to allocate header"); |
561 | goto fail; | | 566 | goto fail; |
562 | } | | 567 | } |
563 | | | 568 | |
564 | kd->kcore_hdr->c_hdrsize = ALIGN(sizeof(kcore_hdr_t)); | | 569 | kd->kcore_hdr->c_hdrsize = ALIGN(sizeof(kcore_hdr_t)); |
565 | kd->kcore_hdr->c_seghdrsize = ALIGN(sizeof(kcore_seg_t)); | | 570 | kd->kcore_hdr->c_seghdrsize = ALIGN(sizeof(kcore_seg_t)); |
566 | kd->kcore_hdr->c_nseg = 2; | | 571 | kd->kcore_hdr->c_nseg = 2; |
567 | CORE_SETMAGIC(*(kd->kcore_hdr), KCORE_MAGIC, MID_MACHINE,0); | | 572 | CORE_SETMAGIC(*(kd->kcore_hdr), KCORE_MAGIC, MID_MACHINE,0); |
568 | | | 573 | |
569 | /* | | 574 | /* |
570 | * Now that we have a valid header, enable translations. | | 575 | * Now that we have a valid header, enable translations. |
571 | */ | | 576 | */ |
572 | if (_kvm_initvtop(kd) == 0) | | 577 | if (_kvm_initvtop(kd) == 0) |
573 | /* Success */ | | 578 | /* Success */ |
574 | return (hdr_size); | | 579 | return (hdr_size); |
575 | | | 580 | |
576 | fail: | | 581 | fail: |
577 | if (kd->kcore_hdr != NULL) { | | 582 | if (kd->kcore_hdr != NULL) { |
578 | free(kd->kcore_hdr); | | 583 | free(kd->kcore_hdr); |
579 | kd->kcore_hdr = NULL; | | 584 | kd->kcore_hdr = NULL; |
580 | } | | 585 | } |
581 | if (kd->cpu_data != NULL) { | | 586 | if (kd->cpu_data != NULL) { |
582 | free(kd->cpu_data); | | 587 | free(kd->cpu_data); |
583 | kd->cpu_data = NULL; | | 588 | kd->cpu_data = NULL; |
584 | kd->cpu_dsize = 0; | | 589 | kd->cpu_dsize = 0; |
585 | } | | 590 | } |
586 | return (-1); | | 591 | return (-1); |
587 | } | | 592 | } |
588 | | | 593 | |
589 | static int | | 594 | static int |
590 | clear_gap(kvm_t *kd, bool (*write_buf)(void *, const void *, size_t), | | 595 | clear_gap(kvm_t *kd, bool (*write_buf)(void *, const void *, size_t), |
591 | void *cookie, size_t size) | | 596 | void *cookie, size_t size) |
592 | { | | 597 | { |
593 | char buf[1024]; | | 598 | char buf[1024]; |
594 | size_t len; | | 599 | size_t len; |
595 | | | 600 | |
596 | (void)memset(buf, 0, size > sizeof(buf) ? sizeof(buf) : size); | | 601 | (void)memset(buf, 0, size > sizeof(buf) ? sizeof(buf) : size); |
597 | | | 602 | |
598 | while (size > 0) { | | 603 | while (size > 0) { |
599 | len = size > sizeof(buf) ? sizeof(buf) : size; | | 604 | len = size > sizeof(buf) ? sizeof(buf) : size; |
600 | if (!(*write_buf)(cookie, buf, len)) { | | 605 | if (!(*write_buf)(cookie, buf, len)) { |
601 | _kvm_syserr(kd, kd->program, "clear_gap"); | | 606 | _kvm_syserr(kd, kd->program, "clear_gap"); |
602 | return -1; | | 607 | return -1; |
603 | } | | 608 | } |
604 | size -= len; | | 609 | size -= len; |
605 | } | | 610 | } |
606 | | | 611 | |
607 | return 0; | | 612 | return 0; |
608 | } | | 613 | } |
609 | | | 614 | |
610 | /* | | 615 | /* |
611 | * Write the dump header by calling write_buf with cookie as first argument. | | 616 | * Write the dump header by calling write_buf with cookie as first argument. |
612 | */ | | 617 | */ |
613 | int | | 618 | int |
614 | kvm_dump_header(kvm_t *kd, bool (*write_buf)(void *, const void *, size_t), | | 619 | kvm_dump_header(kvm_t *kd, bool (*write_buf)(void *, const void *, size_t), |
615 | void *cookie, int dumpsize) | | 620 | void *cookie, int dumpsize) |
616 | { | | 621 | { |
617 | kcore_seg_t seghdr; | | 622 | kcore_seg_t seghdr; |
618 | long offset; | | 623 | long offset; |
619 | size_t gap; | | 624 | size_t gap; |
620 | | | 625 | |
621 | if (kd->kcore_hdr == NULL || kd->cpu_data == NULL) { | | 626 | if (kd->kcore_hdr == NULL || kd->cpu_data == NULL) { |
622 | _kvm_err(kd, kd->program, "no valid dump header(s)"); | | 627 | _kvm_err(kd, kd->program, "no valid dump header(s)"); |
623 | return (-1); | | 628 | return (-1); |
624 | } | | 629 | } |
625 | | | 630 | |
626 | /* | | 631 | /* |
627 | * Write the generic header | | 632 | * Write the generic header |
628 | */ | | 633 | */ |
629 | offset = 0; | | 634 | offset = 0; |
630 | if (!(*write_buf)(cookie, kd->kcore_hdr, sizeof(kcore_hdr_t))) { | | 635 | if (!(*write_buf)(cookie, kd->kcore_hdr, sizeof(kcore_hdr_t))) { |
631 | _kvm_syserr(kd, kd->program, "kvm_dump_header"); | | 636 | _kvm_syserr(kd, kd->program, "kvm_dump_header"); |
632 | return (-1); | | 637 | return (-1); |
633 | } | | 638 | } |
634 | offset += kd->kcore_hdr->c_hdrsize; | | 639 | offset += kd->kcore_hdr->c_hdrsize; |
635 | gap = kd->kcore_hdr->c_hdrsize - sizeof(kcore_hdr_t); | | 640 | gap = kd->kcore_hdr->c_hdrsize - sizeof(kcore_hdr_t); |
636 | if (clear_gap(kd, write_buf, cookie, gap) == -1) | | 641 | if (clear_gap(kd, write_buf, cookie, gap) == -1) |
637 | return (-1); | | 642 | return (-1); |
638 | | | 643 | |
639 | /* | | 644 | /* |
640 | * Write the CPU header | | 645 | * Write the CPU header |
641 | */ | | 646 | */ |
642 | CORE_SETMAGIC(seghdr, KCORESEG_MAGIC, 0, CORE_CPU); | | 647 | CORE_SETMAGIC(seghdr, KCORESEG_MAGIC, 0, CORE_CPU); |
643 | seghdr.c_size = ALIGN(kd->cpu_dsize); | | 648 | seghdr.c_size = ALIGN(kd->cpu_dsize); |
644 | if (!(*write_buf)(cookie, &seghdr, sizeof(seghdr))) { | | 649 | if (!(*write_buf)(cookie, &seghdr, sizeof(seghdr))) { |
645 | _kvm_syserr(kd, kd->program, "kvm_dump_header"); | | 650 | _kvm_syserr(kd, kd->program, "kvm_dump_header"); |
646 | return (-1); | | 651 | return (-1); |
647 | } | | 652 | } |
648 | offset += kd->kcore_hdr->c_seghdrsize; | | 653 | offset += kd->kcore_hdr->c_seghdrsize; |
649 | gap = kd->kcore_hdr->c_seghdrsize - sizeof(seghdr); | | 654 | gap = kd->kcore_hdr->c_seghdrsize - sizeof(seghdr); |
650 | if (clear_gap(kd, write_buf, cookie, gap) == -1) | | 655 | if (clear_gap(kd, write_buf, cookie, gap) == -1) |
651 | return (-1); | | 656 | return (-1); |
652 | | | 657 | |
653 | if (!(*write_buf)(cookie, kd->cpu_data, kd->cpu_dsize)) { | | 658 | if (!(*write_buf)(cookie, kd->cpu_data, kd->cpu_dsize)) { |
654 | _kvm_syserr(kd, kd->program, "kvm_dump_header"); | | 659 | _kvm_syserr(kd, kd->program, "kvm_dump_header"); |
655 | return (-1); | | 660 | return (-1); |
656 | } | | 661 | } |
657 | offset += seghdr.c_size; | | 662 | offset += seghdr.c_size; |
658 | gap = seghdr.c_size - kd->cpu_dsize; | | 663 | gap = seghdr.c_size - kd->cpu_dsize; |
659 | if (clear_gap(kd, write_buf, cookie, gap) == -1) | | 664 | if (clear_gap(kd, write_buf, cookie, gap) == -1) |
660 | return (-1); | | 665 | return (-1); |
661 | | | 666 | |
662 | /* | | 667 | /* |
663 | * Write the actual dump data segment header | | 668 | * Write the actual dump data segment header |
664 | */ | | 669 | */ |
665 | CORE_SETMAGIC(seghdr, KCORESEG_MAGIC, 0, CORE_DATA); | | 670 | CORE_SETMAGIC(seghdr, KCORESEG_MAGIC, 0, CORE_DATA); |
666 | seghdr.c_size = dumpsize; | | 671 | seghdr.c_size = dumpsize; |
667 | if (!(*write_buf)(cookie, &seghdr, sizeof(seghdr))) { | | 672 | if (!(*write_buf)(cookie, &seghdr, sizeof(seghdr))) { |
668 | _kvm_syserr(kd, kd->program, "kvm_dump_header"); | | 673 | _kvm_syserr(kd, kd->program, "kvm_dump_header"); |
669 | return (-1); | | 674 | return (-1); |
670 | } | | 675 | } |
671 | offset += kd->kcore_hdr->c_seghdrsize; | | 676 | offset += kd->kcore_hdr->c_seghdrsize; |
672 | gap = kd->kcore_hdr->c_seghdrsize - sizeof(seghdr); | | 677 | gap = kd->kcore_hdr->c_seghdrsize - sizeof(seghdr); |
673 | if (clear_gap(kd, write_buf, cookie, gap) == -1) | | 678 | if (clear_gap(kd, write_buf, cookie, gap) == -1) |
674 | return (-1); | | 679 | return (-1); |
675 | | | 680 | |
676 | return (int)offset; | | 681 | return (int)offset; |
677 | } | | 682 | } |
678 | | | 683 | |
679 | static bool | | 684 | static bool |
680 | kvm_dump_header_stdio(void *cookie, const void *buf, size_t len) | | 685 | kvm_dump_header_stdio(void *cookie, const void *buf, size_t len) |
681 | { | | 686 | { |
682 | return fwrite(buf, len, 1, (FILE *)cookie) == 1; | | 687 | return fwrite(buf, len, 1, (FILE *)cookie) == 1; |
683 | } | | 688 | } |
684 | | | 689 | |
685 | int | | 690 | int |
686 | kvm_dump_wrtheader(kvm_t *kd, FILE *fp, int dumpsize) | | 691 | kvm_dump_wrtheader(kvm_t *kd, FILE *fp, int dumpsize) |
687 | { | | 692 | { |
688 | return kvm_dump_header(kd, kvm_dump_header_stdio, fp, dumpsize); | | 693 | return kvm_dump_header(kd, kvm_dump_header_stdio, fp, dumpsize); |
689 | } | | 694 | } |
690 | | | 695 | |
691 | kvm_t * | | 696 | kvm_t * |
692 | kvm_openfiles(const char *uf, const char *mf, const char *sf, | | 697 | kvm_openfiles(const char *uf, const char *mf, const char *sf, |
693 | int flag, char *errout) | | 698 | int flag, char *errout) |
694 | { | | 699 | { |
695 | kvm_t *kd; | | 700 | kvm_t *kd; |
696 | | | 701 | |
697 | if ((kd = malloc(sizeof(*kd))) == NULL) { | | 702 | if ((kd = malloc(sizeof(*kd))) == NULL) { |
698 | (void)strlcpy(errout, strerror(errno), _POSIX2_LINE_MAX); | | 703 | (void)strlcpy(errout, strerror(errno), _POSIX2_LINE_MAX); |
699 | return (0); | | 704 | return (0); |
700 | } | | 705 | } |
701 | kd->program = 0; | | 706 | kd->program = 0; |
702 | return (_kvm_open(kd, uf, mf, sf, flag, errout)); | | 707 | return (_kvm_open(kd, uf, mf, sf, flag, errout)); |
703 | } | | 708 | } |
704 | | | 709 | |
705 | kvm_t * | | 710 | kvm_t * |
706 | kvm_open(const char *uf, const char *mf, const char *sf, int flag, | | 711 | kvm_open(const char *uf, const char *mf, const char *sf, int flag, |
707 | const char *program) | | 712 | const char *program) |
708 | { | | 713 | { |
709 | kvm_t *kd; | | 714 | kvm_t *kd; |
710 | | | 715 | |
711 | if ((kd = malloc(sizeof(*kd))) == NULL) { | | 716 | if ((kd = malloc(sizeof(*kd))) == NULL) { |
712 | (void)fprintf(stderr, "%s: %s\n", | | 717 | (void)fprintf(stderr, "%s: %s\n", |
713 | program ? program : getprogname(), strerror(errno)); | | 718 | program ? program : getprogname(), strerror(errno)); |
714 | return (0); | | 719 | return (0); |
715 | } | | 720 | } |
716 | kd->program = program; | | 721 | kd->program = program; |
717 | return (_kvm_open(kd, uf, mf, sf, flag, NULL)); | | 722 | return (_kvm_open(kd, uf, mf, sf, flag, NULL)); |
718 | } | | 723 | } |
719 | | | 724 | |
720 | int | | 725 | int |
721 | kvm_close(kvm_t *kd) | | 726 | kvm_close(kvm_t *kd) |
722 | { | | 727 | { |
723 | int error = 0; | | 728 | int error = 0; |
724 | | | 729 | |
725 | if (kd->pmfd >= 0) | | 730 | if (kd->pmfd >= 0) |
726 | error |= close(kd->pmfd); | | 731 | error |= close(kd->pmfd); |
727 | if (kd->vmfd >= 0) | | 732 | if (kd->vmfd >= 0) |
728 | error |= close(kd->vmfd); | | 733 | error |= close(kd->vmfd); |
729 | if (kd->nlfd >= 0) | | 734 | if (kd->nlfd >= 0) |
730 | error |= close(kd->nlfd); | | 735 | error |= close(kd->nlfd); |
731 | if (kd->swfd >= 0) | | 736 | if (kd->swfd >= 0) |
732 | error |= close(kd->swfd); | | 737 | error |= close(kd->swfd); |
733 | if (kd->vmst) | | 738 | if (kd->vmst) |
734 | _kvm_freevtop(kd); | | 739 | _kvm_freevtop(kd); |
735 | kd->cpu_dsize = 0; | | 740 | kd->cpu_dsize = 0; |
736 | if (kd->cpu_data != NULL) | | 741 | if (kd->cpu_data != NULL) |
737 | free(kd->cpu_data); | | 742 | free(kd->cpu_data); |
738 | if (kd->kcore_hdr != NULL) | | 743 | if (kd->kcore_hdr != NULL) |
739 | free(kd->kcore_hdr); | | 744 | free(kd->kcore_hdr); |
740 | if (kd->procbase != 0) | | 745 | if (kd->procbase != 0) |
741 | free(kd->procbase); | | 746 | free(kd->procbase); |
742 | if (kd->procbase2 != 0) | | 747 | if (kd->procbase2 != 0) |
743 | free(kd->procbase2); | | 748 | free(kd->procbase2); |
744 | if (kd->lwpbase != 0) | | 749 | if (kd->lwpbase != 0) |
745 | free(kd->lwpbase); | | 750 | free(kd->lwpbase); |
746 | if (kd->swapspc != 0) | | 751 | if (kd->swapspc != 0) |
747 | free(kd->swapspc); | | 752 | free(kd->swapspc); |
748 | if (kd->argspc != 0) | | 753 | if (kd->argspc != 0) |
749 | free(kd->argspc); | | 754 | free(kd->argspc); |
750 | if (kd->argbuf != 0) | | 755 | if (kd->argbuf != 0) |
751 | free(kd->argbuf); | | 756 | free(kd->argbuf); |
752 | if (kd->argv != 0) | | 757 | if (kd->argv != 0) |
753 | free(kd->argv); | | 758 | free(kd->argv); |
754 | if (kd->iobuf != 0) | | 759 | if (kd->iobuf != 0) |
755 | free(kd->iobuf); | | 760 | free(kd->iobuf); |
756 | free(kd); | | 761 | free(kd); |
757 | | | 762 | |
758 | return (error); | | 763 | return (error); |
759 | } | | 764 | } |
760 | | | 765 | |
761 | int | | 766 | int |
762 | kvm_nlist(kvm_t *kd, struct nlist *nl) | | 767 | kvm_nlist(kvm_t *kd, struct nlist *nl) |
763 | { | | 768 | { |
764 | int rv; | | 769 | int rv; |
765 | | | 770 | |
766 | /* | | 771 | /* |
767 | * Call the nlist(3) routines to retrieve the given namelist. | | 772 | * Call the nlist(3) routines to retrieve the given namelist. |
768 | */ | | 773 | */ |
769 | rv = __fdnlist(kd->nlfd, nl); | | 774 | rv = __fdnlist(kd->nlfd, nl); |
770 | | | 775 | |
771 | if (rv == -1) | | 776 | if (rv == -1) |
772 | _kvm_err(kd, 0, "bad namelist"); | | 777 | _kvm_err(kd, 0, "bad namelist"); |
773 | | | 778 | |
774 | return (rv); | | 779 | return (rv); |
775 | } | | 780 | } |
776 | | | 781 | |
777 | int | | 782 | int |
778 | kvm_dump_inval(kvm_t *kd) | | 783 | kvm_dump_inval(kvm_t *kd) |
779 | { | | 784 | { |
780 | struct nlist nl[2]; | | 785 | struct nlist nl[2]; |
781 | paddr_t pa; | | 786 | paddr_t pa; |
782 | size_t dsize; | | 787 | size_t dsize; |
783 | off_t doff; | | 788 | off_t doff; |
784 | void *newbuf; | | 789 | void *newbuf; |
785 | | | 790 | |
786 | if (ISALIVE(kd)) { | | 791 | if (ISALIVE(kd)) { |
787 | _kvm_err(kd, kd->program, "clearing dump on live kernel"); | | 792 | _kvm_err(kd, kd->program, "clearing dump on live kernel"); |
788 | return (-1); | | 793 | return (-1); |
789 | } | | 794 | } |
790 | nl[0].n_name = "_dumpmag"; | | 795 | nl[0].n_name = "_dumpmag"; |
791 | nl[1].n_name = NULL; | | 796 | nl[1].n_name = NULL; |
792 | | | 797 | |
793 | if (kvm_nlist(kd, nl) == -1) { | | 798 | if (kvm_nlist(kd, nl) == -1) { |
794 | _kvm_err(kd, 0, "bad namelist"); | | 799 | _kvm_err(kd, 0, "bad namelist"); |
795 | return (-1); | | 800 | return (-1); |
796 | } | | 801 | } |
797 | if (_kvm_kvatop(kd, (vaddr_t)nl[0].n_value, &pa) == 0) | | 802 | if (_kvm_kvatop(kd, (vaddr_t)nl[0].n_value, &pa) == 0) |
798 | return (-1); | | 803 | return (-1); |
799 | | | 804 | |
800 | errno = 0; | | 805 | errno = 0; |
801 | dsize = MAX(kd->fdalign, sizeof(u_long)); | | 806 | dsize = MAX(kd->fdalign, sizeof(u_long)); |
802 | if (kd->iobufsz < dsize) { | | 807 | if (kd->iobufsz < dsize) { |
803 | newbuf = realloc(kd->iobuf, dsize); | | 808 | newbuf = realloc(kd->iobuf, dsize); |
804 | if (newbuf == NULL) { | | 809 | if (newbuf == NULL) { |
805 | _kvm_syserr(kd, 0, "cannot allocate I/O buffer"); | | 810 | _kvm_syserr(kd, 0, "cannot allocate I/O buffer"); |
806 | return (-1); | | 811 | return (-1); |
807 | } | | 812 | } |
808 | kd->iobuf = newbuf; | | 813 | kd->iobuf = newbuf; |
809 | kd->iobufsz = dsize; | | 814 | kd->iobufsz = dsize; |
810 | } | | 815 | } |
811 | memset(kd->iobuf, 0, dsize); | | 816 | memset(kd->iobuf, 0, dsize); |
812 | doff = _kvm_pa2off(kd, pa); | | 817 | doff = _kvm_pa2off(kd, pa); |
813 | doff -= doff % kd->fdalign; | | 818 | doff -= doff % kd->fdalign; |
814 | if (pwrite(kd->pmfd, kd->iobuf, dsize, doff) == -1) { | | 819 | if (pwrite(kd->pmfd, kd->iobuf, dsize, doff) == -1) { |
815 | _kvm_syserr(kd, 0, "cannot invalidate dump - pwrite"); | | 820 | _kvm_syserr(kd, 0, "cannot invalidate dump - pwrite"); |
816 | return (-1); | | 821 | return (-1); |
817 | } | | 822 | } |
818 | return (0); | | 823 | return (0); |
819 | } | | 824 | } |
820 | | | 825 | |
821 | ssize_t | | 826 | ssize_t |
822 | kvm_read(kvm_t *kd, u_long kva, void *buf, size_t len) | | 827 | kvm_read(kvm_t *kd, u_long kva, void *buf, size_t len) |
823 | { | | 828 | { |
824 | int cc; | | 829 | int cc; |
825 | void *cp; | | 830 | void *cp; |
826 | | | 831 | |
827 | if (ISKMEM(kd)) { | | 832 | if (ISKMEM(kd)) { |
828 | /* | | 833 | /* |
829 | * We're using /dev/kmem. Just read straight from the | | 834 | * We're using /dev/kmem. Just read straight from the |
830 | * device and let the active kernel do the address translation. | | 835 | * device and let the active kernel do the address translation. |
831 | */ | | 836 | */ |
832 | errno = 0; | | 837 | errno = 0; |
833 | cc = _kvm_pread(kd, kd->vmfd, buf, len, (off_t)kva); | | 838 | cc = _kvm_pread(kd, kd->vmfd, buf, len, (off_t)kva); |
834 | if (cc < 0) { | | 839 | if (cc < 0) { |
835 | _kvm_syserr(kd, 0, "kvm_read"); | | 840 | _kvm_syserr(kd, 0, "kvm_read"); |
836 | return (-1); | | 841 | return (-1); |
837 | } else if (cc < len) | | 842 | } else if (cc < len) |
838 | _kvm_err(kd, kd->program, "short read"); | | 843 | _kvm_err(kd, kd->program, "short read"); |
839 | return (cc); | | 844 | return (cc); |
840 | } else if (ISSYSCTL(kd)) { | | 845 | } else if (ISSYSCTL(kd)) { |
841 | _kvm_err(kd, kd->program, "kvm_open called with KVM_NO_FILES, " | | 846 | _kvm_err(kd, kd->program, "kvm_open called with KVM_NO_FILES, " |
842 | "can't use kvm_read"); | | 847 | "can't use kvm_read"); |
843 | return (-1); | | 848 | return (-1); |
844 | } else { | | 849 | } else { |
845 | if ((kd->kcore_hdr == NULL) || (kd->cpu_data == NULL)) { | | 850 | if ((kd->kcore_hdr == NULL) || (kd->cpu_data == NULL)) { |
846 | _kvm_err(kd, kd->program, "no valid dump header"); | | 851 | _kvm_err(kd, kd->program, "no valid dump header"); |
847 | return (-1); | | 852 | return (-1); |
848 | } | | 853 | } |
849 | cp = buf; | | 854 | cp = buf; |
850 | while (len > 0) { | | 855 | while (len > 0) { |
851 | paddr_t pa; | | 856 | paddr_t pa; |
852 | off_t foff; | | 857 | off_t foff; |
853 | | | 858 | |
854 | cc = _kvm_kvatop(kd, (vaddr_t)kva, &pa); | | 859 | cc = _kvm_kvatop(kd, (vaddr_t)kva, &pa); |
855 | if (cc == 0) { | | 860 | if (cc == 0) { |
856 | _kvm_err(kd, kd->program, "_kvm_kvatop(%lx)", kva); | | 861 | _kvm_err(kd, kd->program, "_kvm_kvatop(%lx)", kva); |
857 | return (-1); | | 862 | return (-1); |
858 | } | | 863 | } |
859 | if (cc > len) | | 864 | if (cc > len) |
860 | cc = len; | | 865 | cc = len; |
861 | foff = _kvm_pa2off(kd, pa); | | 866 | foff = _kvm_pa2off(kd, pa); |
862 | errno = 0; | | 867 | errno = 0; |
863 | cc = _kvm_pread(kd, kd->pmfd, cp, (size_t)cc, foff); | | 868 | cc = _kvm_pread(kd, kd->pmfd, cp, (size_t)cc, foff); |
864 | if (cc < 0) { | | 869 | if (cc < 0) { |
865 | _kvm_syserr(kd, kd->program, "kvm_read"); | | 870 | _kvm_syserr(kd, kd->program, "kvm_read"); |
866 | break; | | 871 | break; |
867 | } | | 872 | } |
868 | /* | | 873 | /* |
869 | * If kvm_kvatop returns a bogus value or our core | | 874 | * If kvm_kvatop returns a bogus value or our core |
870 | * file is truncated, we might wind up seeking beyond | | 875 | * file is truncated, we might wind up seeking beyond |
871 | * the end of the core file in which case the read will | | 876 | * the end of the core file in which case the read will |
872 | * return 0 (EOF). | | 877 | * return 0 (EOF). |
873 | */ | | 878 | */ |
874 | if (cc == 0) | | 879 | if (cc == 0) |
875 | break; | | 880 | break; |
876 | cp = (char *)cp + cc; | | 881 | cp = (char *)cp + cc; |
877 | kva += cc; | | 882 | kva += cc; |
878 | len -= cc; | | 883 | len -= cc; |
879 | } | | 884 | } |
880 | return ((char *)cp - (char *)buf); | | 885 | return ((char *)cp - (char *)buf); |
881 | } | | 886 | } |
882 | /* NOTREACHED */ | | 887 | /* NOTREACHED */ |
883 | } | | 888 | } |
884 | | | 889 | |
885 | ssize_t | | 890 | ssize_t |
886 | kvm_write(kvm_t *kd, u_long kva, const void *buf, size_t len) | | 891 | kvm_write(kvm_t *kd, u_long kva, const void *buf, size_t len) |
887 | { | | 892 | { |
888 | int cc; | | 893 | int cc; |
889 | | | 894 | |
890 | if (ISKMEM(kd)) { | | 895 | if (ISKMEM(kd)) { |
891 | /* | | 896 | /* |
892 | * Just like kvm_read, only we write. | | 897 | * Just like kvm_read, only we write. |
893 | */ | | 898 | */ |
894 | errno = 0; | | 899 | errno = 0; |
895 | cc = pwrite(kd->vmfd, buf, len, (off_t)kva); | | 900 | cc = pwrite(kd->vmfd, buf, len, (off_t)kva); |
896 | if (cc < 0) { | | 901 | if (cc < 0) { |
897 | _kvm_syserr(kd, 0, "kvm_write"); | | 902 | _kvm_syserr(kd, 0, "kvm_write"); |
898 | return (-1); | | 903 | return (-1); |
899 | } else if (cc < len) | | 904 | } else if (cc < len) |
900 | _kvm_err(kd, kd->program, "short write"); | | 905 | _kvm_err(kd, kd->program, "short write"); |
901 | return (cc); | | 906 | return (cc); |
902 | } else if (ISSYSCTL(kd)) { | | 907 | } else if (ISSYSCTL(kd)) { |
903 | _kvm_err(kd, kd->program, "kvm_open called with KVM_NO_FILES, " | | 908 | _kvm_err(kd, kd->program, "kvm_open called with KVM_NO_FILES, " |
904 | "can't use kvm_write"); | | 909 | "can't use kvm_write"); |
905 | return (-1); | | 910 | return (-1); |
906 | } else { | | 911 | } else { |
907 | _kvm_err(kd, kd->program, | | 912 | _kvm_err(kd, kd->program, |
908 | "kvm_write not implemented for dead kernels"); | | 913 | "kvm_write not implemented for dead kernels"); |
909 | return (-1); | | 914 | return (-1); |
910 | } | | 915 | } |
911 | /* NOTREACHED */ | | 916 | /* NOTREACHED */ |
912 | } | | 917 | } |