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