1 |
|
|
/* $OpenBSD: kvm_proc.c,v 1.58 2016/11/07 00:26:33 guenther Exp $ */ |
2 |
|
|
/* $NetBSD: kvm_proc.c,v 1.30 1999/03/24 05:50:50 mrg Exp $ */ |
3 |
|
|
/*- |
4 |
|
|
* Copyright (c) 1998 The NetBSD Foundation, Inc. |
5 |
|
|
* All rights reserved. |
6 |
|
|
* |
7 |
|
|
* This code is derived from software contributed to The NetBSD Foundation |
8 |
|
|
* by Charles M. Hannum. |
9 |
|
|
* |
10 |
|
|
* Redistribution and use in source and binary forms, with or without |
11 |
|
|
* modification, are permitted provided that the following conditions |
12 |
|
|
* are met: |
13 |
|
|
* 1. Redistributions of source code must retain the above copyright |
14 |
|
|
* notice, this list of conditions and the following disclaimer. |
15 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
16 |
|
|
* notice, this list of conditions and the following disclaimer in the |
17 |
|
|
* documentation and/or other materials provided with the distribution. |
18 |
|
|
* |
19 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 |
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 |
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 |
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 |
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 |
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 |
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 |
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 |
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 |
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 |
|
|
* POSSIBILITY OF SUCH DAMAGE. |
30 |
|
|
*/ |
31 |
|
|
/*- |
32 |
|
|
* Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved. |
33 |
|
|
* Copyright (c) 1989, 1992, 1993 |
34 |
|
|
* The Regents of the University of California. All rights reserved. |
35 |
|
|
* |
36 |
|
|
* This code is derived from software developed by the Computer Systems |
37 |
|
|
* Engineering group at Lawrence Berkeley Laboratory under DARPA contract |
38 |
|
|
* BG 91-66 and contributed to Berkeley. |
39 |
|
|
* |
40 |
|
|
* Redistribution and use in source and binary forms, with or without |
41 |
|
|
* modification, are permitted provided that the following conditions |
42 |
|
|
* are met: |
43 |
|
|
* 1. Redistributions of source code must retain the above copyright |
44 |
|
|
* notice, this list of conditions and the following disclaimer. |
45 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
46 |
|
|
* notice, this list of conditions and the following disclaimer in the |
47 |
|
|
* documentation and/or other materials provided with the distribution. |
48 |
|
|
* 3. Neither the name of the University nor the names of its contributors |
49 |
|
|
* may be used to endorse or promote products derived from this software |
50 |
|
|
* without specific prior written permission. |
51 |
|
|
* |
52 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
53 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
54 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
55 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
56 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
57 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
58 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
59 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
60 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
61 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
62 |
|
|
* SUCH DAMAGE. |
63 |
|
|
*/ |
64 |
|
|
|
65 |
|
|
/* |
66 |
|
|
* Proc traversal interface for kvm. ps and w are (probably) the exclusive |
67 |
|
|
* users of this code, so we've factored it out into a separate module. |
68 |
|
|
* Thus, we keep this grunge out of the other kvm applications (i.e., |
69 |
|
|
* most other applications are interested only in open/close/read/nlist). |
70 |
|
|
*/ |
71 |
|
|
|
72 |
|
|
#define __need_process |
73 |
|
|
#include <sys/param.h> |
74 |
|
|
#include <sys/proc.h> |
75 |
|
|
#include <sys/exec.h> |
76 |
|
|
#include <sys/stat.h> |
77 |
|
|
#include <sys/ioctl.h> |
78 |
|
|
#include <sys/tty.h> |
79 |
|
|
#include <stdlib.h> |
80 |
|
|
#include <string.h> |
81 |
|
|
#include <unistd.h> |
82 |
|
|
#include <nlist.h> |
83 |
|
|
#include <kvm.h> |
84 |
|
|
#include <errno.h> |
85 |
|
|
|
86 |
|
|
#include <uvm/uvm_extern.h> |
87 |
|
|
#include <uvm/uvm_amap.h> |
88 |
|
|
#include <machine/vmparam.h> |
89 |
|
|
#include <machine/pmap.h> |
90 |
|
|
|
91 |
|
|
#include <sys/sysctl.h> |
92 |
|
|
|
93 |
|
|
#include <limits.h> |
94 |
|
|
#include <db.h> |
95 |
|
|
#include <paths.h> |
96 |
|
|
|
97 |
|
|
#include "kvm_private.h" |
98 |
|
|
|
99 |
|
|
|
100 |
|
|
static char *_kvm_ureadm(kvm_t *, const struct kinfo_proc *, u_long, u_long *); |
101 |
|
|
static ssize_t kvm_ureadm(kvm_t *, const struct kinfo_proc *, u_long, char *, size_t); |
102 |
|
|
|
103 |
|
|
static char **kvm_argv(kvm_t *, const struct kinfo_proc *, u_long, int, int); |
104 |
|
|
|
105 |
|
|
static char **kvm_doargv(kvm_t *, const struct kinfo_proc *, int, |
106 |
|
|
void (*)(struct ps_strings *, u_long *, int *)); |
107 |
|
|
static int proc_verify(kvm_t *, const struct kinfo_proc *); |
108 |
|
|
static void ps_str_a(struct ps_strings *, u_long *, int *); |
109 |
|
|
static void ps_str_e(struct ps_strings *, u_long *, int *); |
110 |
|
|
|
111 |
|
|
static struct vm_anon * |
112 |
|
|
_kvm_findanon(kvm_t *kd, struct vm_amap *amapp, int slot) |
113 |
|
|
{ |
114 |
|
|
u_long addr; |
115 |
|
|
int bucket; |
116 |
|
|
struct vm_amap amap; |
117 |
|
|
struct vm_amap_chunk chunk, *chunkp; |
118 |
|
|
struct vm_anon *anonp; |
119 |
|
|
|
120 |
|
|
addr = (u_long)amapp; |
121 |
|
|
if (KREAD(kd, addr, &amap)) |
122 |
|
|
return (NULL); |
123 |
|
|
|
124 |
|
|
/* sanity-check slot number */ |
125 |
|
|
if (slot > amap.am_nslot) |
126 |
|
|
return (NULL); |
127 |
|
|
|
128 |
|
|
if (UVM_AMAP_SMALL(&amap)) |
129 |
|
|
chunkp = &amapp->am_small; |
130 |
|
|
else { |
131 |
|
|
bucket = UVM_AMAP_BUCKET(&amap, slot); |
132 |
|
|
addr = (u_long)(amap.am_buckets + bucket); |
133 |
|
|
if (KREAD(kd, addr, &chunkp)) |
134 |
|
|
return (NULL); |
135 |
|
|
|
136 |
|
|
while (chunkp != NULL) { |
137 |
|
|
addr = (u_long)chunkp; |
138 |
|
|
if (KREAD(kd, addr, &chunk)) |
139 |
|
|
return (NULL); |
140 |
|
|
|
141 |
|
|
if (UVM_AMAP_BUCKET(&amap, chunk.ac_baseslot) != |
142 |
|
|
bucket) |
143 |
|
|
return (NULL); |
144 |
|
|
if (slot >= chunk.ac_baseslot && |
145 |
|
|
slot < chunk.ac_baseslot + chunk.ac_nslot) |
146 |
|
|
break; |
147 |
|
|
|
148 |
|
|
chunkp = TAILQ_NEXT(&chunk, ac_list); |
149 |
|
|
} |
150 |
|
|
if (chunkp == NULL) |
151 |
|
|
return (NULL); |
152 |
|
|
} |
153 |
|
|
|
154 |
|
|
addr = (u_long)&chunkp->ac_anon[UVM_AMAP_SLOTIDX(slot)]; |
155 |
|
|
if (KREAD(kd, addr, &anonp)) |
156 |
|
|
return (NULL); |
157 |
|
|
|
158 |
|
|
return (anonp); |
159 |
|
|
} |
160 |
|
|
|
161 |
|
|
static char * |
162 |
|
|
_kvm_ureadm(kvm_t *kd, const struct kinfo_proc *p, u_long va, u_long *cnt) |
163 |
|
|
{ |
164 |
|
|
u_long addr, offset, slot; |
165 |
|
|
struct vmspace vm; |
166 |
|
|
struct vm_anon *anonp, anon; |
167 |
|
|
struct vm_map_entry vme; |
168 |
|
|
struct vm_page pg; |
169 |
|
|
unsigned long rboff; |
170 |
|
|
|
171 |
|
|
if (kd->swapspc == 0) { |
172 |
|
|
kd->swapspc = _kvm_malloc(kd, kd->nbpg); |
173 |
|
|
if (kd->swapspc == 0) |
174 |
|
|
return (NULL); |
175 |
|
|
} |
176 |
|
|
|
177 |
|
|
rboff = (unsigned long)&vme.daddrs.addr_entry - (unsigned long)&vme; |
178 |
|
|
|
179 |
|
|
/* |
180 |
|
|
* Look through the address map for the memory object |
181 |
|
|
* that corresponds to the given virtual address. |
182 |
|
|
*/ |
183 |
|
|
if (KREAD(kd, (u_long)p->p_vmspace, &vm)) |
184 |
|
|
return (NULL); |
185 |
|
|
addr = (u_long)&vm.vm_map.addr.rbh_root.rbt_root; |
186 |
|
|
while (1) { |
187 |
|
|
if (addr == 0) |
188 |
|
|
return (NULL); |
189 |
|
|
addr -= rboff; |
190 |
|
|
if (KREAD(kd, addr, &vme)) |
191 |
|
|
return (NULL); |
192 |
|
|
|
193 |
|
|
if (va < vme.start) |
194 |
|
|
addr = (u_long)vme.daddrs.addr_entry.rbt_left; |
195 |
|
|
else if (va >= vme.end + vme.guard + vme.fspace) |
196 |
|
|
addr = (u_long)vme.daddrs.addr_entry.rbt_right; |
197 |
|
|
else if (va >= vme.end) |
198 |
|
|
return (NULL); |
199 |
|
|
else |
200 |
|
|
break; |
201 |
|
|
} |
202 |
|
|
|
203 |
|
|
/* |
204 |
|
|
* we found the map entry, now to find the object... |
205 |
|
|
*/ |
206 |
|
|
if (vme.aref.ar_amap == NULL) |
207 |
|
|
return (NULL); |
208 |
|
|
|
209 |
|
|
offset = va - vme.start; |
210 |
|
|
slot = offset / kd->nbpg + vme.aref.ar_pageoff; |
211 |
|
|
|
212 |
|
|
anonp = _kvm_findanon(kd, vme.aref.ar_amap, slot); |
213 |
|
|
if (anonp == NULL) |
214 |
|
|
return (NULL); |
215 |
|
|
|
216 |
|
|
addr = (u_long)anonp; |
217 |
|
|
if (KREAD(kd, addr, &anon)) |
218 |
|
|
return (NULL); |
219 |
|
|
|
220 |
|
|
addr = (u_long)anon.an_page; |
221 |
|
|
if (addr) { |
222 |
|
|
if (KREAD(kd, addr, &pg)) |
223 |
|
|
return (NULL); |
224 |
|
|
|
225 |
|
|
if (_kvm_pread(kd, kd->pmfd, (void *)kd->swapspc, |
226 |
|
|
(size_t)kd->nbpg, (off_t)pg.phys_addr) != kd->nbpg) |
227 |
|
|
return (NULL); |
228 |
|
|
} else { |
229 |
|
|
if (kd->swfd == -1 || |
230 |
|
|
_kvm_pread(kd, kd->swfd, (void *)kd->swapspc, |
231 |
|
|
(size_t)kd->nbpg, |
232 |
|
|
(off_t)(anon.an_swslot * kd->nbpg)) != kd->nbpg) |
233 |
|
|
return (NULL); |
234 |
|
|
} |
235 |
|
|
|
236 |
|
|
/* Found the page. */ |
237 |
|
|
offset %= kd->nbpg; |
238 |
|
|
*cnt = kd->nbpg - offset; |
239 |
|
|
return (&kd->swapspc[offset]); |
240 |
|
|
} |
241 |
|
|
|
242 |
|
|
void * |
243 |
|
|
_kvm_reallocarray(kvm_t *kd, void *p, size_t i, size_t n) |
244 |
|
|
{ |
245 |
|
|
void *np = reallocarray(p, i, n); |
246 |
|
|
|
247 |
|
|
if (np == 0) |
248 |
|
|
_kvm_err(kd, kd->program, "out of memory"); |
249 |
|
|
return (np); |
250 |
|
|
} |
251 |
|
|
|
252 |
|
|
/* |
253 |
|
|
* Read in an argument vector from the user address space of process p. |
254 |
|
|
* addr if the user-space base address of narg null-terminated contiguous |
255 |
|
|
* strings. This is used to read in both the command arguments and |
256 |
|
|
* environment strings. Read at most maxcnt characters of strings. |
257 |
|
|
*/ |
258 |
|
|
static char ** |
259 |
|
|
kvm_argv(kvm_t *kd, const struct kinfo_proc *p, u_long addr, int narg, |
260 |
|
|
int maxcnt) |
261 |
|
|
{ |
262 |
|
|
char *np, *cp, *ep, *ap, **argv; |
263 |
|
|
u_long oaddr = -1; |
264 |
|
|
int len, cc; |
265 |
|
|
|
266 |
|
|
/* |
267 |
|
|
* Check that there aren't an unreasonable number of arguments, |
268 |
|
|
* and that the address is in user space. |
269 |
|
|
*/ |
270 |
|
|
if (narg > ARG_MAX || addr < VM_MIN_ADDRESS || addr >= VM_MAXUSER_ADDRESS) |
271 |
|
|
return (0); |
272 |
|
|
|
273 |
|
|
if (kd->argv == 0) { |
274 |
|
|
/* |
275 |
|
|
* Try to avoid reallocs. |
276 |
|
|
*/ |
277 |
|
|
kd->argc = MAX(narg + 1, 32); |
278 |
|
|
kd->argv = _kvm_reallocarray(kd, NULL, kd->argc, |
279 |
|
|
sizeof(*kd->argv)); |
280 |
|
|
if (kd->argv == 0) |
281 |
|
|
return (0); |
282 |
|
|
} else if (narg + 1 > kd->argc) { |
283 |
|
|
kd->argc = MAX(2 * kd->argc, narg + 1); |
284 |
|
|
kd->argv = (char **)_kvm_reallocarray(kd, kd->argv, kd->argc, |
285 |
|
|
sizeof(*kd->argv)); |
286 |
|
|
if (kd->argv == 0) |
287 |
|
|
return (0); |
288 |
|
|
} |
289 |
|
|
if (kd->argspc == 0) { |
290 |
|
|
kd->argspc = _kvm_malloc(kd, kd->nbpg); |
291 |
|
|
if (kd->argspc == 0) |
292 |
|
|
return (0); |
293 |
|
|
kd->arglen = kd->nbpg; |
294 |
|
|
} |
295 |
|
|
if (kd->argbuf == 0) { |
296 |
|
|
kd->argbuf = _kvm_malloc(kd, kd->nbpg); |
297 |
|
|
if (kd->argbuf == 0) |
298 |
|
|
return (0); |
299 |
|
|
} |
300 |
|
|
cc = sizeof(char *) * narg; |
301 |
|
|
if (kvm_ureadm(kd, p, addr, (char *)kd->argv, cc) != cc) |
302 |
|
|
return (0); |
303 |
|
|
ap = np = kd->argspc; |
304 |
|
|
argv = kd->argv; |
305 |
|
|
len = 0; |
306 |
|
|
|
307 |
|
|
/* |
308 |
|
|
* Loop over pages, filling in the argument vector. |
309 |
|
|
*/ |
310 |
|
|
while (argv < kd->argv + narg && *argv != 0) { |
311 |
|
|
addr = (u_long)*argv & ~(kd->nbpg - 1); |
312 |
|
|
if (addr != oaddr) { |
313 |
|
|
if (kvm_ureadm(kd, p, addr, kd->argbuf, kd->nbpg) != |
314 |
|
|
kd->nbpg) |
315 |
|
|
return (0); |
316 |
|
|
oaddr = addr; |
317 |
|
|
} |
318 |
|
|
addr = (u_long)*argv & (kd->nbpg - 1); |
319 |
|
|
cp = kd->argbuf + addr; |
320 |
|
|
cc = kd->nbpg - addr; |
321 |
|
|
if (maxcnt > 0 && cc > maxcnt - len) |
322 |
|
|
cc = maxcnt - len; |
323 |
|
|
ep = memchr(cp, '\0', cc); |
324 |
|
|
if (ep != 0) |
325 |
|
|
cc = ep - cp + 1; |
326 |
|
|
if (len + cc > kd->arglen) { |
327 |
|
|
int off; |
328 |
|
|
char **pp; |
329 |
|
|
char *op = kd->argspc; |
330 |
|
|
char *newp; |
331 |
|
|
|
332 |
|
|
newp = _kvm_reallocarray(kd, kd->argspc, |
333 |
|
|
kd->arglen, 2); |
334 |
|
|
if (newp == 0) |
335 |
|
|
return (0); |
336 |
|
|
kd->argspc = newp; |
337 |
|
|
kd->arglen *= 2; |
338 |
|
|
/* |
339 |
|
|
* Adjust argv pointers in case realloc moved |
340 |
|
|
* the string space. |
341 |
|
|
*/ |
342 |
|
|
off = kd->argspc - op; |
343 |
|
|
for (pp = kd->argv; pp < argv; pp++) |
344 |
|
|
*pp += off; |
345 |
|
|
ap += off; |
346 |
|
|
np += off; |
347 |
|
|
} |
348 |
|
|
memcpy(np, cp, cc); |
349 |
|
|
np += cc; |
350 |
|
|
len += cc; |
351 |
|
|
if (ep != 0) { |
352 |
|
|
*argv++ = ap; |
353 |
|
|
ap = np; |
354 |
|
|
} else |
355 |
|
|
*argv += cc; |
356 |
|
|
if (maxcnt > 0 && len >= maxcnt) { |
357 |
|
|
/* |
358 |
|
|
* We're stopping prematurely. Terminate the |
359 |
|
|
* current string. |
360 |
|
|
*/ |
361 |
|
|
if (ep == 0) { |
362 |
|
|
*np = '\0'; |
363 |
|
|
*argv++ = ap; |
364 |
|
|
} |
365 |
|
|
break; |
366 |
|
|
} |
367 |
|
|
} |
368 |
|
|
/* Make sure argv is terminated. */ |
369 |
|
|
*argv = 0; |
370 |
|
|
return (kd->argv); |
371 |
|
|
} |
372 |
|
|
|
373 |
|
|
static void |
374 |
|
|
ps_str_a(struct ps_strings *p, u_long *addr, int *n) |
375 |
|
|
{ |
376 |
|
|
*addr = (u_long)p->ps_argvstr; |
377 |
|
|
*n = p->ps_nargvstr; |
378 |
|
|
} |
379 |
|
|
|
380 |
|
|
static void |
381 |
|
|
ps_str_e(struct ps_strings *p, u_long *addr, int *n) |
382 |
|
|
{ |
383 |
|
|
*addr = (u_long)p->ps_envstr; |
384 |
|
|
*n = p->ps_nenvstr; |
385 |
|
|
} |
386 |
|
|
|
387 |
|
|
/* |
388 |
|
|
* Determine if the proc indicated by p is still active. |
389 |
|
|
* This test is not 100% foolproof in theory, but chances of |
390 |
|
|
* being wrong are very low. |
391 |
|
|
*/ |
392 |
|
|
static int |
393 |
|
|
proc_verify(kvm_t *kd, const struct kinfo_proc *p) |
394 |
|
|
{ |
395 |
|
|
struct proc kernproc; |
396 |
|
|
struct process kernprocess; |
397 |
|
|
|
398 |
|
|
if (p->p_psflags & (PS_EMBRYO | PS_ZOMBIE)) |
399 |
|
|
return (0); |
400 |
|
|
|
401 |
|
|
/* |
402 |
|
|
* Just read in the whole proc. It's not that big relative |
403 |
|
|
* to the cost of the read system call. |
404 |
|
|
*/ |
405 |
|
|
if (KREAD(kd, (u_long)p->p_paddr, &kernproc)) |
406 |
|
|
return (0); |
407 |
|
|
if (KREAD(kd, (u_long)kernproc.p_p, &kernprocess)) |
408 |
|
|
return (0); |
409 |
|
|
if (p->p_pid != kernprocess.ps_pid) |
410 |
|
|
return (0); |
411 |
|
|
return ((kernprocess.ps_flags & (PS_EMBRYO | PS_ZOMBIE)) == 0); |
412 |
|
|
} |
413 |
|
|
|
414 |
|
|
static char ** |
415 |
|
|
kvm_doargv(kvm_t *kd, const struct kinfo_proc *p, int nchr, |
416 |
|
|
void (*info)(struct ps_strings *, u_long *, int *)) |
417 |
|
|
{ |
418 |
|
|
static struct ps_strings *ps; |
419 |
|
|
struct ps_strings arginfo; |
420 |
|
|
u_long addr; |
421 |
|
|
char **ap; |
422 |
|
|
int cnt; |
423 |
|
|
|
424 |
|
|
if (ps == NULL) { |
425 |
|
|
struct _ps_strings _ps; |
426 |
|
|
int mib[2]; |
427 |
|
|
size_t len; |
428 |
|
|
|
429 |
|
|
mib[0] = CTL_VM; |
430 |
|
|
mib[1] = VM_PSSTRINGS; |
431 |
|
|
len = sizeof(_ps); |
432 |
|
|
sysctl(mib, 2, &_ps, &len, NULL, 0); |
433 |
|
|
ps = (struct ps_strings *)_ps.val; |
434 |
|
|
} |
435 |
|
|
|
436 |
|
|
/* |
437 |
|
|
* Pointers are stored at the top of the user stack. |
438 |
|
|
*/ |
439 |
|
|
if (p->p_psflags & (PS_EMBRYO | PS_ZOMBIE) || |
440 |
|
|
kvm_ureadm(kd, p, (u_long)ps, (char *)&arginfo, |
441 |
|
|
sizeof(arginfo)) != sizeof(arginfo)) |
442 |
|
|
return (0); |
443 |
|
|
|
444 |
|
|
(*info)(&arginfo, &addr, &cnt); |
445 |
|
|
if (cnt == 0) |
446 |
|
|
return (0); |
447 |
|
|
ap = kvm_argv(kd, p, addr, cnt, nchr); |
448 |
|
|
/* |
449 |
|
|
* For live kernels, make sure this process didn't go away. |
450 |
|
|
*/ |
451 |
|
|
if (ap != 0 && ISALIVE(kd) && !proc_verify(kd, p)) |
452 |
|
|
ap = 0; |
453 |
|
|
return (ap); |
454 |
|
|
} |
455 |
|
|
|
456 |
|
|
static char ** |
457 |
|
|
kvm_arg_sysctl(kvm_t *kd, pid_t pid, int nchr, int env) |
458 |
|
|
{ |
459 |
|
3370 |
size_t len, orglen; |
460 |
|
1685 |
int mib[4], ret; |
461 |
|
|
char *buf; |
462 |
|
|
|
463 |
|
1685 |
orglen = env ? kd->nbpg : 8 * kd->nbpg; /* XXX - should be ARG_MAX */ |
464 |
✓✓✗✓
|
2376 |
if (kd->argbuf == NULL && |
465 |
|
691 |
(kd->argbuf = _kvm_malloc(kd, orglen)) == NULL) |
466 |
|
|
return (NULL); |
467 |
|
|
|
468 |
|
|
again: |
469 |
|
1685 |
mib[0] = CTL_KERN; |
470 |
|
1685 |
mib[1] = KERN_PROC_ARGS; |
471 |
|
1685 |
mib[2] = (int)pid; |
472 |
|
1685 |
mib[3] = env ? KERN_PROC_ENV : KERN_PROC_ARGV; |
473 |
|
|
|
474 |
|
1685 |
len = orglen; |
475 |
|
1685 |
ret = (sysctl(mib, 4, kd->argbuf, &len, NULL, 0) < 0); |
476 |
✓✓✗✓
|
1865 |
if (ret && errno == ENOMEM) { |
477 |
|
|
buf = _kvm_reallocarray(kd, kd->argbuf, orglen, 2); |
478 |
|
|
if (buf == NULL) |
479 |
|
|
return (NULL); |
480 |
|
|
orglen *= 2; |
481 |
|
|
kd->argbuf = buf; |
482 |
|
|
goto again; |
483 |
|
|
} |
484 |
|
|
|
485 |
✓✓ |
1685 |
if (ret) { |
486 |
|
180 |
free(kd->argbuf); |
487 |
|
180 |
kd->argbuf = NULL; |
488 |
|
180 |
_kvm_syserr(kd, kd->program, "kvm_arg_sysctl"); |
489 |
|
180 |
return (NULL); |
490 |
|
|
} |
491 |
|
|
#if 0 |
492 |
|
|
for (argv = (char **)kd->argbuf; *argv != NULL; argv++) |
493 |
|
|
if (strlen(*argv) > nchr) |
494 |
|
|
*argv[nchr] = '\0'; |
495 |
|
|
#endif |
496 |
|
|
|
497 |
|
1505 |
return (char **)(kd->argbuf); |
498 |
|
1685 |
} |
499 |
|
|
|
500 |
|
|
/* |
501 |
|
|
* Get the command args. This code is now machine independent. |
502 |
|
|
*/ |
503 |
|
|
char ** |
504 |
|
|
kvm_getargv(kvm_t *kd, const struct kinfo_proc *kp, int nchr) |
505 |
|
|
{ |
506 |
✓✗ |
2670 |
if (ISALIVE(kd)) |
507 |
|
1335 |
return (kvm_arg_sysctl(kd, kp->p_pid, nchr, 0)); |
508 |
|
|
return (kvm_doargv(kd, kp, nchr, ps_str_a)); |
509 |
|
1335 |
} |
510 |
|
|
|
511 |
|
|
char ** |
512 |
|
|
kvm_getenvv(kvm_t *kd, const struct kinfo_proc *kp, int nchr) |
513 |
|
|
{ |
514 |
✓✗ |
700 |
if (ISALIVE(kd)) |
515 |
|
350 |
return (kvm_arg_sysctl(kd, kp->p_pid, nchr, 1)); |
516 |
|
|
return (kvm_doargv(kd, kp, nchr, ps_str_e)); |
517 |
|
350 |
} |
518 |
|
|
|
519 |
|
|
/* |
520 |
|
|
* Read from user space. The user context is given by p. |
521 |
|
|
*/ |
522 |
|
|
static ssize_t |
523 |
|
|
kvm_ureadm(kvm_t *kd, const struct kinfo_proc *p, u_long uva, char *buf, |
524 |
|
|
size_t len) |
525 |
|
|
{ |
526 |
|
|
char *cp = buf; |
527 |
|
|
|
528 |
|
|
while (len > 0) { |
529 |
|
|
u_long cnt; |
530 |
|
|
size_t cc; |
531 |
|
|
char *dp; |
532 |
|
|
|
533 |
|
|
dp = _kvm_ureadm(kd, p, uva, &cnt); |
534 |
|
|
if (dp == 0) { |
535 |
|
|
_kvm_err(kd, 0, "invalid address (%lx)", uva); |
536 |
|
|
return (0); |
537 |
|
|
} |
538 |
|
|
cc = (size_t)MIN(cnt, len); |
539 |
|
|
memcpy(cp, dp, cc); |
540 |
|
|
cp += cc; |
541 |
|
|
uva += cc; |
542 |
|
|
len -= cc; |
543 |
|
|
} |
544 |
|
|
return (ssize_t)(cp - buf); |
545 |
|
|
} |