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
10struct kinfo_vmentry *
11kinfo_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