1185493Speter#include <sys/cdefs.h>
2185493Speter__FBSDID("$FreeBSD: stable/10/lib/libutil/kinfo_getvmmap.c 312032 2017-01-13 08:39:40Z ngie $");
3185493Speter
4186512Srwatson#include <sys/param.h>
5312032Sngie#include <sys/sysctl.h>
6185493Speter#include <sys/user.h>
7185493Speter#include <stdlib.h>
8185493Speter#include <string.h>
9185493Speter
10185493Speter#include "libutil.h"
11185493Speter
12185493Speterstruct kinfo_vmentry *
13185493Speterkinfo_getvmmap(pid_t pid, int *cntp)
14185493Speter{
15185493Speter	int mib[4];
16185493Speter	int error;
17185493Speter	int cnt;
18185493Speter	size_t len;
19185493Speter	char *buf, *bp, *eb;
20185493Speter	struct kinfo_vmentry *kiv, *kp, *kv;
21185493Speter
22186314Smarcus	*cntp = 0;
23185493Speter	len = 0;
24185493Speter	mib[0] = CTL_KERN;
25185493Speter	mib[1] = KERN_PROC;
26185493Speter	mib[2] = KERN_PROC_VMMAP;
27185493Speter	mib[3] = pid;
28185493Speter
29312032Sngie	error = sysctl(mib, nitems(mib), NULL, &len, NULL, 0);
30185493Speter	if (error)
31186314Smarcus		return (NULL);
32185493Speter	len = len * 4 / 3;
33185493Speter	buf = malloc(len);
34185493Speter	if (buf == NULL)
35186314Smarcus		return (NULL);
36312032Sngie	error = sysctl(mib, nitems(mib), buf, &len, NULL, 0);
37185493Speter	if (error) {
38185493Speter		free(buf);
39186314Smarcus		return (NULL);
40185493Speter	}
41185493Speter	/* Pass 1: count items */
42185493Speter	cnt = 0;
43185493Speter	bp = buf;
44185493Speter	eb = buf + len;
45185493Speter	while (bp < eb) {
46185553Speter		kv = (struct kinfo_vmentry *)(uintptr_t)bp;
47295454Sjhb		if (kv->kve_structsize == 0)
48295454Sjhb			break;
49185493Speter		bp += kv->kve_structsize;
50185493Speter		cnt++;
51185493Speter	}
52185493Speter
53185493Speter	kiv = calloc(cnt, sizeof(*kiv));
54185493Speter	if (kiv == NULL) {
55185493Speter		free(buf);
56186314Smarcus		return (NULL);
57185493Speter	}
58185493Speter	bp = buf;
59185493Speter	eb = buf + len;
60185493Speter	kp = kiv;
61185493Speter	/* Pass 2: unpack */
62185493Speter	while (bp < eb) {
63185553Speter		kv = (struct kinfo_vmentry *)(uintptr_t)bp;
64295454Sjhb		if (kv->kve_structsize == 0)
65295454Sjhb			break;
66185493Speter		/* Copy/expand into pre-zeroed buffer */
67185493Speter		memcpy(kp, kv, kv->kve_structsize);
68185493Speter		/* Advance to next packed record */
69185493Speter		bp += kv->kve_structsize;
70185493Speter		/* Set field size to fixed length, advance */
71185493Speter		kp->kve_structsize = sizeof(*kp);
72185493Speter		kp++;
73185493Speter	}
74185493Speter	free(buf);
75185493Speter	*cntp = cnt;
76185493Speter	return (kiv);	/* Caller must free() return value */
77185493Speter}
78