xref: /freebsd/lib/libutil/kinfo_getvmmap.c (revision 6ef644f5889afbd0f681b08ed1a2f369524af83e)
1 #include <sys/cdefs.h>
2 #include <sys/param.h>
3 #include <sys/sysctl.h>
4 #include <sys/user.h>
5 #include <stdlib.h>
6 #include <string.h>
7 
8 #include "libutil.h"
9 
10 struct kinfo_vmentry *
11 kinfo_getvmmap(pid_t pid, int *cntp)
12 {
13 	int mib[4];
14 	int error;
15 	int cnt;
16 	size_t len;
17 	char *buf, *bp, *eb;
18 	struct kinfo_vmentry *kiv, *kp, *kv;
19 
20 	*cntp = 0;
21 	len = 0;
22 	mib[0] = CTL_KERN;
23 	mib[1] = KERN_PROC;
24 	mib[2] = KERN_PROC_VMMAP;
25 	mib[3] = pid;
26 
27 	error = sysctl(mib, nitems(mib), NULL, &len, NULL, 0);
28 	if (error)
29 		return (NULL);
30 	len = len * 4 / 3;
31 	buf = malloc(len);
32 	if (buf == NULL)
33 		return (NULL);
34 	error = sysctl(mib, nitems(mib), buf, &len, NULL, 0);
35 	if (error) {
36 		free(buf);
37 		return (NULL);
38 	}
39 	/* Pass 1: count items */
40 	cnt = 0;
41 	bp = buf;
42 	eb = buf + len;
43 	while (bp < eb) {
44 		kv = (struct kinfo_vmentry *)(uintptr_t)bp;
45 		if (kv->kve_structsize == 0)
46 			break;
47 		bp += kv->kve_structsize;
48 		cnt++;
49 	}
50 
51 	kiv = calloc(cnt, sizeof(*kiv));
52 	if (kiv == NULL) {
53 		free(buf);
54 		return (NULL);
55 	}
56 	bp = buf;
57 	eb = buf + len;
58 	kp = kiv;
59 	/* Pass 2: unpack */
60 	while (bp < eb) {
61 		kv = (struct kinfo_vmentry *)(uintptr_t)bp;
62 		if (kv->kve_structsize == 0)
63 			break;
64 		/* Copy/expand into pre-zeroed buffer */
65 		memcpy(kp, kv, kv->kve_structsize);
66 		/* Advance to next packed record */
67 		bp += kv->kve_structsize;
68 		/* Set field size to fixed length, advance */
69 		kp->kve_structsize = sizeof(*kp);
70 		kp++;
71 	}
72 	free(buf);
73 	*cntp = cnt;
74 	return (kiv);	/* Caller must free() return value */
75 }
76