1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate *
4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate * with the License.
8*7c478bd9Sstevel@tonic-gate *
9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate *
14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate *
20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate * Copyright 2001-2003 Sun Microsystems, Inc. All rights reserved.
24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate */
26*7c478bd9Sstevel@tonic-gate
27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
28*7c478bd9Sstevel@tonic-gate
29*7c478bd9Sstevel@tonic-gate #include <stdio.h>
30*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
31*7c478bd9Sstevel@tonic-gate #include <unistd.h>
32*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
33*7c478bd9Sstevel@tonic-gate #include <ctype.h>
34*7c478bd9Sstevel@tonic-gate #include <string.h>
35*7c478bd9Sstevel@tonic-gate #include <signal.h>
36*7c478bd9Sstevel@tonic-gate #include <errno.h>
37*7c478bd9Sstevel@tonic-gate #include <dirent.h>
38*7c478bd9Sstevel@tonic-gate #include <limits.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/mman.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/wait.h>
43*7c478bd9Sstevel@tonic-gate #include <libproc.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
45*7c478bd9Sstevel@tonic-gate #include <libgen.h>
46*7c478bd9Sstevel@tonic-gate #include <thread.h>
47*7c478bd9Sstevel@tonic-gate
48*7c478bd9Sstevel@tonic-gate #ifndef TRUE
49*7c478bd9Sstevel@tonic-gate #define TRUE 1
50*7c478bd9Sstevel@tonic-gate #endif
51*7c478bd9Sstevel@tonic-gate #ifndef FALSE
52*7c478bd9Sstevel@tonic-gate #define FALSE 0
53*7c478bd9Sstevel@tonic-gate #endif
54*7c478bd9Sstevel@tonic-gate
55*7c478bd9Sstevel@tonic-gate static struct ps_prochandle *Pr;
56*7c478bd9Sstevel@tonic-gate static char *command;
57*7c478bd9Sstevel@tonic-gate static volatile int interrupt;
58*7c478bd9Sstevel@tonic-gate static int Fflag;
59*7c478bd9Sstevel@tonic-gate static int cflag = 1;
60*7c478bd9Sstevel@tonic-gate
61*7c478bd9Sstevel@tonic-gate static void intr(int);
62*7c478bd9Sstevel@tonic-gate static int setpgsz(struct ps_prochandle *, int, size_t *);
63*7c478bd9Sstevel@tonic-gate static int setpgsz_anon(struct ps_prochandle *, size_t, int);
64*7c478bd9Sstevel@tonic-gate static caddr_t setup_mha(uint_t, size_t, int);
65*7c478bd9Sstevel@tonic-gate static size_t discover_optimal_pagesize(struct ps_prochandle *,
66*7c478bd9Sstevel@tonic-gate uint_t, pid_t);
67*7c478bd9Sstevel@tonic-gate static void usage();
68*7c478bd9Sstevel@tonic-gate
69*7c478bd9Sstevel@tonic-gate #define INVPGSZ 3
70*7c478bd9Sstevel@tonic-gate
71*7c478bd9Sstevel@tonic-gate /* subopt */
72*7c478bd9Sstevel@tonic-gate
73*7c478bd9Sstevel@tonic-gate static char *suboptstr[] = {
74*7c478bd9Sstevel@tonic-gate "heap",
75*7c478bd9Sstevel@tonic-gate "stack",
76*7c478bd9Sstevel@tonic-gate "anon",
77*7c478bd9Sstevel@tonic-gate NULL
78*7c478bd9Sstevel@tonic-gate };
79*7c478bd9Sstevel@tonic-gate
80*7c478bd9Sstevel@tonic-gate enum suboptenum {
81*7c478bd9Sstevel@tonic-gate E_HEAP,
82*7c478bd9Sstevel@tonic-gate E_STACK,
83*7c478bd9Sstevel@tonic-gate E_ANON
84*7c478bd9Sstevel@tonic-gate };
85*7c478bd9Sstevel@tonic-gate
86*7c478bd9Sstevel@tonic-gate static size_t
atosz(char * optarg)87*7c478bd9Sstevel@tonic-gate atosz(char *optarg)
88*7c478bd9Sstevel@tonic-gate {
89*7c478bd9Sstevel@tonic-gate size_t sz = 0;
90*7c478bd9Sstevel@tonic-gate char *endptr;
91*7c478bd9Sstevel@tonic-gate
92*7c478bd9Sstevel@tonic-gate if (optarg == NULL || optarg[0] == '\0')
93*7c478bd9Sstevel@tonic-gate return (INVPGSZ);
94*7c478bd9Sstevel@tonic-gate
95*7c478bd9Sstevel@tonic-gate sz = strtoll(optarg, &endptr, 0);
96*7c478bd9Sstevel@tonic-gate
97*7c478bd9Sstevel@tonic-gate switch (*endptr) {
98*7c478bd9Sstevel@tonic-gate case 'T':
99*7c478bd9Sstevel@tonic-gate case 't':
100*7c478bd9Sstevel@tonic-gate sz *= 1024;
101*7c478bd9Sstevel@tonic-gate /*FALLTHRU*/
102*7c478bd9Sstevel@tonic-gate case 'G':
103*7c478bd9Sstevel@tonic-gate case 'g':
104*7c478bd9Sstevel@tonic-gate sz *= 1024;
105*7c478bd9Sstevel@tonic-gate /*FALLTHRU*/
106*7c478bd9Sstevel@tonic-gate case 'M':
107*7c478bd9Sstevel@tonic-gate case 'm':
108*7c478bd9Sstevel@tonic-gate sz *= 1024;
109*7c478bd9Sstevel@tonic-gate /*FALLTHRU*/
110*7c478bd9Sstevel@tonic-gate case 'K':
111*7c478bd9Sstevel@tonic-gate case 'k':
112*7c478bd9Sstevel@tonic-gate sz *= 1024;
113*7c478bd9Sstevel@tonic-gate /*FALLTHRU*/
114*7c478bd9Sstevel@tonic-gate case 'B':
115*7c478bd9Sstevel@tonic-gate case 'b':
116*7c478bd9Sstevel@tonic-gate default:
117*7c478bd9Sstevel@tonic-gate break;
118*7c478bd9Sstevel@tonic-gate }
119*7c478bd9Sstevel@tonic-gate return (sz);
120*7c478bd9Sstevel@tonic-gate }
121*7c478bd9Sstevel@tonic-gate
122*7c478bd9Sstevel@tonic-gate /* pgsz array sufficient for max page sizes */
123*7c478bd9Sstevel@tonic-gate
124*7c478bd9Sstevel@tonic-gate static size_t pgsza[8 * sizeof (void *)];
125*7c478bd9Sstevel@tonic-gate static int nelem;
126*7c478bd9Sstevel@tonic-gate
127*7c478bd9Sstevel@tonic-gate static void
getpgsz()128*7c478bd9Sstevel@tonic-gate getpgsz()
129*7c478bd9Sstevel@tonic-gate {
130*7c478bd9Sstevel@tonic-gate if ((nelem = getpagesizes(NULL, 0)) == 0) {
131*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: cannot determine system page"
132*7c478bd9Sstevel@tonic-gate " sizes\n", command);
133*7c478bd9Sstevel@tonic-gate exit(125);
134*7c478bd9Sstevel@tonic-gate }
135*7c478bd9Sstevel@tonic-gate
136*7c478bd9Sstevel@tonic-gate (void) getpagesizes(pgsza, nelem);
137*7c478bd9Sstevel@tonic-gate }
138*7c478bd9Sstevel@tonic-gate
139*7c478bd9Sstevel@tonic-gate static size_t
cnvpgsz(char * optarg)140*7c478bd9Sstevel@tonic-gate cnvpgsz(char *optarg)
141*7c478bd9Sstevel@tonic-gate {
142*7c478bd9Sstevel@tonic-gate size_t pgsz = atosz(optarg);
143*7c478bd9Sstevel@tonic-gate int i;
144*7c478bd9Sstevel@tonic-gate
145*7c478bd9Sstevel@tonic-gate if (!ISP2(pgsz) || ((pgsz < pgsza[0]) && pgsz != 0)) {
146*7c478bd9Sstevel@tonic-gate pgsz = INVPGSZ;
147*7c478bd9Sstevel@tonic-gate } else {
148*7c478bd9Sstevel@tonic-gate for (i = nelem - 1; i >= 0; i--) {
149*7c478bd9Sstevel@tonic-gate if (pgsz == pgsza[i])
150*7c478bd9Sstevel@tonic-gate break;
151*7c478bd9Sstevel@tonic-gate if (pgsz > pgsza[i]) {
152*7c478bd9Sstevel@tonic-gate pgsz = INVPGSZ;
153*7c478bd9Sstevel@tonic-gate break;
154*7c478bd9Sstevel@tonic-gate }
155*7c478bd9Sstevel@tonic-gate }
156*7c478bd9Sstevel@tonic-gate }
157*7c478bd9Sstevel@tonic-gate if (pgsz == INVPGSZ) {
158*7c478bd9Sstevel@tonic-gate if (optarg != NULL) {
159*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
160*7c478bd9Sstevel@tonic-gate "%s: invalid page size specified (%s)\n",
161*7c478bd9Sstevel@tonic-gate command, optarg);
162*7c478bd9Sstevel@tonic-gate } else {
163*7c478bd9Sstevel@tonic-gate usage();
164*7c478bd9Sstevel@tonic-gate }
165*7c478bd9Sstevel@tonic-gate exit(125);
166*7c478bd9Sstevel@tonic-gate }
167*7c478bd9Sstevel@tonic-gate return (pgsz);
168*7c478bd9Sstevel@tonic-gate }
169*7c478bd9Sstevel@tonic-gate
170*7c478bd9Sstevel@tonic-gate static void
usage()171*7c478bd9Sstevel@tonic-gate usage()
172*7c478bd9Sstevel@tonic-gate {
173*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
174*7c478bd9Sstevel@tonic-gate "usage:\t%s -o option[,option] [-F] cmd | -p pid ...\n"
175*7c478bd9Sstevel@tonic-gate " (set preferred page size of cmd or each process)\n"
176*7c478bd9Sstevel@tonic-gate " -o option[,option]: options are\n"
177*7c478bd9Sstevel@tonic-gate " stack=sz\n"
178*7c478bd9Sstevel@tonic-gate " heap=sz\n"
179*7c478bd9Sstevel@tonic-gate " anon=sz (sz: valid page size or 0 (zero))\n"
180*7c478bd9Sstevel@tonic-gate " -F: force grabbing of the target process(es)\n"
181*7c478bd9Sstevel@tonic-gate " cmd: launch command\n"
182*7c478bd9Sstevel@tonic-gate " -p pid ...: process id list\n",
183*7c478bd9Sstevel@tonic-gate command);
184*7c478bd9Sstevel@tonic-gate exit(125);
185*7c478bd9Sstevel@tonic-gate }
186*7c478bd9Sstevel@tonic-gate
187*7c478bd9Sstevel@tonic-gate int
main(int argc,char * argv[])188*7c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
189*7c478bd9Sstevel@tonic-gate {
190*7c478bd9Sstevel@tonic-gate int rc, err = 0;
191*7c478bd9Sstevel@tonic-gate int opt, subopt;
192*7c478bd9Sstevel@tonic-gate int errflg = 0;
193*7c478bd9Sstevel@tonic-gate char *options, *value;
194*7c478bd9Sstevel@tonic-gate size_t pgsz[] = {INVPGSZ, INVPGSZ, INVPGSZ};
195*7c478bd9Sstevel@tonic-gate pid_t pid;
196*7c478bd9Sstevel@tonic-gate int status;
197*7c478bd9Sstevel@tonic-gate
198*7c478bd9Sstevel@tonic-gate if ((command = strrchr(argv[0], '/')) != NULL)
199*7c478bd9Sstevel@tonic-gate command++;
200*7c478bd9Sstevel@tonic-gate else
201*7c478bd9Sstevel@tonic-gate command = argv[0];
202*7c478bd9Sstevel@tonic-gate
203*7c478bd9Sstevel@tonic-gate getpgsz();
204*7c478bd9Sstevel@tonic-gate
205*7c478bd9Sstevel@tonic-gate /* options */
206*7c478bd9Sstevel@tonic-gate while ((opt = getopt(argc, argv, "o:Fp")) != EOF) {
207*7c478bd9Sstevel@tonic-gate switch (opt) {
208*7c478bd9Sstevel@tonic-gate case 'o': /* options */
209*7c478bd9Sstevel@tonic-gate options = optarg;
210*7c478bd9Sstevel@tonic-gate while (*options != '\0') {
211*7c478bd9Sstevel@tonic-gate subopt = getsubopt(&options, suboptstr, &value);
212*7c478bd9Sstevel@tonic-gate switch (subopt) {
213*7c478bd9Sstevel@tonic-gate case E_HEAP:
214*7c478bd9Sstevel@tonic-gate case E_STACK:
215*7c478bd9Sstevel@tonic-gate case E_ANON:
216*7c478bd9Sstevel@tonic-gate pgsz[subopt] = cnvpgsz(value);
217*7c478bd9Sstevel@tonic-gate break;
218*7c478bd9Sstevel@tonic-gate default:
219*7c478bd9Sstevel@tonic-gate errflg = 1;
220*7c478bd9Sstevel@tonic-gate break;
221*7c478bd9Sstevel@tonic-gate }
222*7c478bd9Sstevel@tonic-gate }
223*7c478bd9Sstevel@tonic-gate break;
224*7c478bd9Sstevel@tonic-gate case 'F': /* force grabbing (no O_EXCL) */
225*7c478bd9Sstevel@tonic-gate Fflag = PGRAB_FORCE;
226*7c478bd9Sstevel@tonic-gate break;
227*7c478bd9Sstevel@tonic-gate case 'p':
228*7c478bd9Sstevel@tonic-gate cflag = 0;
229*7c478bd9Sstevel@tonic-gate break;
230*7c478bd9Sstevel@tonic-gate default:
231*7c478bd9Sstevel@tonic-gate errflg = 1;
232*7c478bd9Sstevel@tonic-gate break;
233*7c478bd9Sstevel@tonic-gate }
234*7c478bd9Sstevel@tonic-gate }
235*7c478bd9Sstevel@tonic-gate
236*7c478bd9Sstevel@tonic-gate argc -= optind;
237*7c478bd9Sstevel@tonic-gate argv += optind;
238*7c478bd9Sstevel@tonic-gate
239*7c478bd9Sstevel@tonic-gate if ((pgsz[E_HEAP] == INVPGSZ && pgsz[E_STACK] == INVPGSZ &&
240*7c478bd9Sstevel@tonic-gate pgsz[E_ANON] == INVPGSZ) || errflg || argc <= 0) {
241*7c478bd9Sstevel@tonic-gate usage();
242*7c478bd9Sstevel@tonic-gate }
243*7c478bd9Sstevel@tonic-gate
244*7c478bd9Sstevel@tonic-gate /* catch signals from terminal */
245*7c478bd9Sstevel@tonic-gate if (sigset(SIGHUP, SIG_IGN) == SIG_DFL)
246*7c478bd9Sstevel@tonic-gate (void) sigset(SIGHUP, intr);
247*7c478bd9Sstevel@tonic-gate if (sigset(SIGINT, SIG_IGN) == SIG_DFL)
248*7c478bd9Sstevel@tonic-gate (void) sigset(SIGINT, intr);
249*7c478bd9Sstevel@tonic-gate if (sigset(SIGQUIT, SIG_IGN) == SIG_DFL)
250*7c478bd9Sstevel@tonic-gate (void) sigset(SIGQUIT, intr);
251*7c478bd9Sstevel@tonic-gate (void) sigset(SIGTERM, intr);
252*7c478bd9Sstevel@tonic-gate
253*7c478bd9Sstevel@tonic-gate if (cflag && !interrupt) { /* command */
254*7c478bd9Sstevel@tonic-gate int err;
255*7c478bd9Sstevel@tonic-gate char path[PATH_MAX];
256*7c478bd9Sstevel@tonic-gate
257*7c478bd9Sstevel@tonic-gate Pr = Pcreate(argv[0], &argv[0], &err, path, sizeof (path));
258*7c478bd9Sstevel@tonic-gate if (Pr == NULL) {
259*7c478bd9Sstevel@tonic-gate switch (err) {
260*7c478bd9Sstevel@tonic-gate case C_PERM:
261*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
262*7c478bd9Sstevel@tonic-gate "%s: cannot control set-id or "
263*7c478bd9Sstevel@tonic-gate "unreadable object file: %s\n",
264*7c478bd9Sstevel@tonic-gate command, path);
265*7c478bd9Sstevel@tonic-gate break;
266*7c478bd9Sstevel@tonic-gate case C_LP64:
267*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
268*7c478bd9Sstevel@tonic-gate "%s: cannot control _LP64 "
269*7c478bd9Sstevel@tonic-gate "program: %s\n", command, path);
270*7c478bd9Sstevel@tonic-gate break;
271*7c478bd9Sstevel@tonic-gate case C_NOEXEC:
272*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: cannot execute "
273*7c478bd9Sstevel@tonic-gate "program: %s\n", command, argv[0]);
274*7c478bd9Sstevel@tonic-gate exit(126);
275*7c478bd9Sstevel@tonic-gate break;
276*7c478bd9Sstevel@tonic-gate case C_NOENT:
277*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: cannot find "
278*7c478bd9Sstevel@tonic-gate "program: %s\n", command, argv[0]);
279*7c478bd9Sstevel@tonic-gate exit(127);
280*7c478bd9Sstevel@tonic-gate break;
281*7c478bd9Sstevel@tonic-gate case C_STRANGE:
282*7c478bd9Sstevel@tonic-gate break;
283*7c478bd9Sstevel@tonic-gate default:
284*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
285*7c478bd9Sstevel@tonic-gate "%s: %s\n", command, Pcreate_error(err));
286*7c478bd9Sstevel@tonic-gate break;
287*7c478bd9Sstevel@tonic-gate }
288*7c478bd9Sstevel@tonic-gate exit(125);
289*7c478bd9Sstevel@tonic-gate }
290*7c478bd9Sstevel@tonic-gate
291*7c478bd9Sstevel@tonic-gate if ((rc = setpgsz(Pr, Pstatus(Pr)->pr_dmodel, pgsz)) != 0) {
292*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: set page size "
293*7c478bd9Sstevel@tonic-gate "failed for program: %s\n", command, argv[0]);
294*7c478bd9Sstevel@tonic-gate (void) pr_exit(Pr, 1);
295*7c478bd9Sstevel@tonic-gate exit(125);
296*7c478bd9Sstevel@tonic-gate }
297*7c478bd9Sstevel@tonic-gate
298*7c478bd9Sstevel@tonic-gate /*
299*7c478bd9Sstevel@tonic-gate * release the command to run, wait for it and
300*7c478bd9Sstevel@tonic-gate * return it's exit status if we can.
301*7c478bd9Sstevel@tonic-gate */
302*7c478bd9Sstevel@tonic-gate Prelease(Pr, 0);
303*7c478bd9Sstevel@tonic-gate do {
304*7c478bd9Sstevel@tonic-gate pid = wait(&status);
305*7c478bd9Sstevel@tonic-gate } while (pid == -1 && errno == EINTR);
306*7c478bd9Sstevel@tonic-gate
307*7c478bd9Sstevel@tonic-gate if (pid == -1) {
308*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: wait() error: %s\n",
309*7c478bd9Sstevel@tonic-gate command, strerror(errno));
310*7c478bd9Sstevel@tonic-gate exit(125);
311*7c478bd9Sstevel@tonic-gate }
312*7c478bd9Sstevel@tonic-gate
313*7c478bd9Sstevel@tonic-gate /*
314*7c478bd9Sstevel@tonic-gate * Pass thru the child's exit value.
315*7c478bd9Sstevel@tonic-gate */
316*7c478bd9Sstevel@tonic-gate if (WIFEXITED(status))
317*7c478bd9Sstevel@tonic-gate exit(WEXITSTATUS(status));
318*7c478bd9Sstevel@tonic-gate exit(status | WCOREFLG);
319*7c478bd9Sstevel@tonic-gate }
320*7c478bd9Sstevel@tonic-gate
321*7c478bd9Sstevel@tonic-gate /* process pids */
322*7c478bd9Sstevel@tonic-gate
323*7c478bd9Sstevel@tonic-gate while (--argc >= 0 && !interrupt) {
324*7c478bd9Sstevel@tonic-gate char *arg;
325*7c478bd9Sstevel@tonic-gate psinfo_t psinfo;
326*7c478bd9Sstevel@tonic-gate int gret;
327*7c478bd9Sstevel@tonic-gate
328*7c478bd9Sstevel@tonic-gate (void) fflush(stdout); /* line-at-a-time */
329*7c478bd9Sstevel@tonic-gate
330*7c478bd9Sstevel@tonic-gate /* get the specified pid and the psinfo struct */
331*7c478bd9Sstevel@tonic-gate arg = *argv++;
332*7c478bd9Sstevel@tonic-gate pid = proc_arg_psinfo(arg, PR_ARG_PIDS, &psinfo, &gret);
333*7c478bd9Sstevel@tonic-gate
334*7c478bd9Sstevel@tonic-gate if (pid == -1) {
335*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: cannot examine pid %s:"
336*7c478bd9Sstevel@tonic-gate " %s\n", command, arg, Pgrab_error(gret));
337*7c478bd9Sstevel@tonic-gate if (!isdigit(arg[0]) && strncmp(arg, "/proc/", 6)) {
338*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
339*7c478bd9Sstevel@tonic-gate "\tdo not use -p option"
340*7c478bd9Sstevel@tonic-gate " to launch a command\n");
341*7c478bd9Sstevel@tonic-gate }
342*7c478bd9Sstevel@tonic-gate err++;
343*7c478bd9Sstevel@tonic-gate } else if ((Pr = Pgrab(pid, Fflag, &gret)) != NULL) {
344*7c478bd9Sstevel@tonic-gate rc = setpgsz(Pr, Pstatus(Pr)->pr_dmodel, pgsz);
345*7c478bd9Sstevel@tonic-gate if (rc != 0) {
346*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: set page size "
347*7c478bd9Sstevel@tonic-gate "failed for pid: %d\n", command, (int)pid);
348*7c478bd9Sstevel@tonic-gate err++;
349*7c478bd9Sstevel@tonic-gate }
350*7c478bd9Sstevel@tonic-gate Prelease(Pr, 0);
351*7c478bd9Sstevel@tonic-gate Pr = NULL;
352*7c478bd9Sstevel@tonic-gate } else {
353*7c478bd9Sstevel@tonic-gate switch (gret) {
354*7c478bd9Sstevel@tonic-gate case G_SYS:
355*7c478bd9Sstevel@tonic-gate proc_unctrl_psinfo(&psinfo);
356*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: cannot set page "
357*7c478bd9Sstevel@tonic-gate "size for system process: %d [ %s ]\n",
358*7c478bd9Sstevel@tonic-gate command, (int)pid, psinfo.pr_psargs);
359*7c478bd9Sstevel@tonic-gate err++;
360*7c478bd9Sstevel@tonic-gate break;
361*7c478bd9Sstevel@tonic-gate case G_SELF:
362*7c478bd9Sstevel@tonic-gate /* do it to own self */
363*7c478bd9Sstevel@tonic-gate rc = setpgsz(NULL, psinfo.pr_dmodel, pgsz);
364*7c478bd9Sstevel@tonic-gate if (rc != 0) {
365*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: set page"
366*7c478bd9Sstevel@tonic-gate "size failed for self: %d\n",
367*7c478bd9Sstevel@tonic-gate command, (int)pid);
368*7c478bd9Sstevel@tonic-gate err++;
369*7c478bd9Sstevel@tonic-gate }
370*7c478bd9Sstevel@tonic-gate break;
371*7c478bd9Sstevel@tonic-gate default:
372*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: %s: %d\n",
373*7c478bd9Sstevel@tonic-gate command, Pgrab_error(gret), (int)pid);
374*7c478bd9Sstevel@tonic-gate err++;
375*7c478bd9Sstevel@tonic-gate break;
376*7c478bd9Sstevel@tonic-gate }
377*7c478bd9Sstevel@tonic-gate }
378*7c478bd9Sstevel@tonic-gate }
379*7c478bd9Sstevel@tonic-gate
380*7c478bd9Sstevel@tonic-gate if (interrupt || err)
381*7c478bd9Sstevel@tonic-gate exit(125);
382*7c478bd9Sstevel@tonic-gate
383*7c478bd9Sstevel@tonic-gate return (0);
384*7c478bd9Sstevel@tonic-gate }
385*7c478bd9Sstevel@tonic-gate
386*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
387*7c478bd9Sstevel@tonic-gate static void
intr(int sig)388*7c478bd9Sstevel@tonic-gate intr(int sig)
389*7c478bd9Sstevel@tonic-gate {
390*7c478bd9Sstevel@tonic-gate interrupt = 1;
391*7c478bd9Sstevel@tonic-gate }
392*7c478bd9Sstevel@tonic-gate
393*7c478bd9Sstevel@tonic-gate /* ------ begin specific code ------ */
394*7c478bd9Sstevel@tonic-gate
395*7c478bd9Sstevel@tonic-gate /* set process page size */
396*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
397*7c478bd9Sstevel@tonic-gate static int
setpgsz(struct ps_prochandle * Pr,int dmodel,size_t pgsz[])398*7c478bd9Sstevel@tonic-gate setpgsz(struct ps_prochandle *Pr, int dmodel, size_t pgsz[])
399*7c478bd9Sstevel@tonic-gate {
400*7c478bd9Sstevel@tonic-gate int rc;
401*7c478bd9Sstevel@tonic-gate int err = 0;
402*7c478bd9Sstevel@tonic-gate caddr_t mpss;
403*7c478bd9Sstevel@tonic-gate int i;
404*7c478bd9Sstevel@tonic-gate static uint_t pgszcmd[] =
405*7c478bd9Sstevel@tonic-gate {MHA_MAPSIZE_BSSBRK, MHA_MAPSIZE_STACK, MHA_MAPSIZE_VA};
406*7c478bd9Sstevel@tonic-gate
407*7c478bd9Sstevel@tonic-gate for (i = E_HEAP; i <= E_ANON; i++) {
408*7c478bd9Sstevel@tonic-gate if (pgsz[i] == INVPGSZ)
409*7c478bd9Sstevel@tonic-gate continue;
410*7c478bd9Sstevel@tonic-gate
411*7c478bd9Sstevel@tonic-gate if (i == E_ANON)
412*7c478bd9Sstevel@tonic-gate rc = setpgsz_anon(Pr, pgsz[i], dmodel);
413*7c478bd9Sstevel@tonic-gate else {
414*7c478bd9Sstevel@tonic-gate mpss = setup_mha(pgszcmd[i], pgsz[i], dmodel);
415*7c478bd9Sstevel@tonic-gate rc = pr_memcntl(Pr, NULL, 0, MC_HAT_ADVISE, mpss, 0, 0);
416*7c478bd9Sstevel@tonic-gate }
417*7c478bd9Sstevel@tonic-gate
418*7c478bd9Sstevel@tonic-gate if (rc < 0) {
419*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: warning: set %s page size "
420*7c478bd9Sstevel@tonic-gate "failed (%s) for pid %d\n", command, suboptstr[i],
421*7c478bd9Sstevel@tonic-gate strerror(errno), (int)Pstatus(Pr)->pr_pid);
422*7c478bd9Sstevel@tonic-gate err++;
423*7c478bd9Sstevel@tonic-gate }
424*7c478bd9Sstevel@tonic-gate }
425*7c478bd9Sstevel@tonic-gate return (err);
426*7c478bd9Sstevel@tonic-gate }
427*7c478bd9Sstevel@tonic-gate
428*7c478bd9Sstevel@tonic-gate
429*7c478bd9Sstevel@tonic-gate /*
430*7c478bd9Sstevel@tonic-gate * Walk through the process' address space segments. Set all anonymous
431*7c478bd9Sstevel@tonic-gate * segments to the new page size.
432*7c478bd9Sstevel@tonic-gate */
433*7c478bd9Sstevel@tonic-gate static int
setpgsz_anon(struct ps_prochandle * Pr,size_t pgsz,int dmodel)434*7c478bd9Sstevel@tonic-gate setpgsz_anon(struct ps_prochandle *Pr, size_t pgsz, int dmodel)
435*7c478bd9Sstevel@tonic-gate {
436*7c478bd9Sstevel@tonic-gate caddr_t mpss;
437*7c478bd9Sstevel@tonic-gate prmap_t map;
438*7c478bd9Sstevel@tonic-gate uintptr_t addr;
439*7c478bd9Sstevel@tonic-gate size_t size;
440*7c478bd9Sstevel@tonic-gate const psinfo_t *psinfo;
441*7c478bd9Sstevel@tonic-gate const pstatus_t *pstatus;
442*7c478bd9Sstevel@tonic-gate int fd;
443*7c478bd9Sstevel@tonic-gate int rc;
444*7c478bd9Sstevel@tonic-gate char path[PATH_MAX];
445*7c478bd9Sstevel@tonic-gate
446*7c478bd9Sstevel@tonic-gate /*
447*7c478bd9Sstevel@tonic-gate * Setting the page size for anonymous segments on a process before it
448*7c478bd9Sstevel@tonic-gate * has run will have no effect, since it has not configured anonymous
449*7c478bd9Sstevel@tonic-gate * memory and the page size setting is not "sticky" inside the kernel.
450*7c478bd9Sstevel@tonic-gate * Any anonymous memory subsequently mapped will have the default page
451*7c478bd9Sstevel@tonic-gate * size.
452*7c478bd9Sstevel@tonic-gate */
453*7c478bd9Sstevel@tonic-gate if (cflag)
454*7c478bd9Sstevel@tonic-gate return (0);
455*7c478bd9Sstevel@tonic-gate
456*7c478bd9Sstevel@tonic-gate if ((psinfo = Ppsinfo(Pr)) == NULL)
457*7c478bd9Sstevel@tonic-gate return (-1);
458*7c478bd9Sstevel@tonic-gate if ((pstatus = Pstatus(Pr)) == NULL)
459*7c478bd9Sstevel@tonic-gate return (-1);
460*7c478bd9Sstevel@tonic-gate
461*7c478bd9Sstevel@tonic-gate if (pgsz == 0)
462*7c478bd9Sstevel@tonic-gate pgsz = discover_optimal_pagesize(Pr, dmodel, psinfo->pr_pid);
463*7c478bd9Sstevel@tonic-gate
464*7c478bd9Sstevel@tonic-gate mpss = setup_mha(MHA_MAPSIZE_VA, pgsz, dmodel);
465*7c478bd9Sstevel@tonic-gate
466*7c478bd9Sstevel@tonic-gate (void) snprintf(path, PATH_MAX, "/proc/%d/map", (int)psinfo->pr_pid);
467*7c478bd9Sstevel@tonic-gate if ((fd = open(path, O_RDONLY)) < 0)
468*7c478bd9Sstevel@tonic-gate return (-1);
469*7c478bd9Sstevel@tonic-gate
470*7c478bd9Sstevel@tonic-gate while (read(fd, &map, sizeof (map)) == sizeof (map)) {
471*7c478bd9Sstevel@tonic-gate if ((map.pr_mflags & MA_ANON) == 0) {
472*7c478bd9Sstevel@tonic-gate /* Not anon. */
473*7c478bd9Sstevel@tonic-gate continue;
474*7c478bd9Sstevel@tonic-gate } else if (map.pr_mflags & MA_SHARED) {
475*7c478bd9Sstevel@tonic-gate /* Can't change pagesize for shared mappings. */
476*7c478bd9Sstevel@tonic-gate continue;
477*7c478bd9Sstevel@tonic-gate } else if (map.pr_vaddr + map.pr_size >
478*7c478bd9Sstevel@tonic-gate pstatus->pr_brkbase &&
479*7c478bd9Sstevel@tonic-gate map.pr_vaddr <
480*7c478bd9Sstevel@tonic-gate pstatus->pr_brkbase + pstatus->pr_brksize) {
481*7c478bd9Sstevel@tonic-gate /* Heap. */
482*7c478bd9Sstevel@tonic-gate continue;
483*7c478bd9Sstevel@tonic-gate } else if (map.pr_vaddr >= pstatus->pr_stkbase &&
484*7c478bd9Sstevel@tonic-gate map.pr_vaddr + map.pr_size <=
485*7c478bd9Sstevel@tonic-gate pstatus->pr_stkbase + pstatus->pr_stksize) {
486*7c478bd9Sstevel@tonic-gate /* Stack. */
487*7c478bd9Sstevel@tonic-gate continue;
488*7c478bd9Sstevel@tonic-gate } else if (map.pr_size < pgsz) {
489*7c478bd9Sstevel@tonic-gate /* Too small. */
490*7c478bd9Sstevel@tonic-gate continue;
491*7c478bd9Sstevel@tonic-gate }
492*7c478bd9Sstevel@tonic-gate
493*7c478bd9Sstevel@tonic-gate /*
494*7c478bd9Sstevel@tonic-gate * Find the first address in the segment that is page-aligned.
495*7c478bd9Sstevel@tonic-gate */
496*7c478bd9Sstevel@tonic-gate if (pgsz == 0 || ((map.pr_vaddr % pgsz) == 0))
497*7c478bd9Sstevel@tonic-gate addr = map.pr_vaddr;
498*7c478bd9Sstevel@tonic-gate else
499*7c478bd9Sstevel@tonic-gate addr = map.pr_vaddr + (pgsz - (map.pr_vaddr % pgsz));
500*7c478bd9Sstevel@tonic-gate
501*7c478bd9Sstevel@tonic-gate /*
502*7c478bd9Sstevel@tonic-gate * Calculate how many pages will fit in the segment.
503*7c478bd9Sstevel@tonic-gate */
504*7c478bd9Sstevel@tonic-gate if (pgsz == 0)
505*7c478bd9Sstevel@tonic-gate size = map.pr_size;
506*7c478bd9Sstevel@tonic-gate else
507*7c478bd9Sstevel@tonic-gate size = map.pr_size - (addr % map.pr_vaddr) -
508*7c478bd9Sstevel@tonic-gate ((map.pr_vaddr + map.pr_size) % pgsz);
509*7c478bd9Sstevel@tonic-gate
510*7c478bd9Sstevel@tonic-gate /*
511*7c478bd9Sstevel@tonic-gate * If no aligned pages fit in the segment, ignore it.
512*7c478bd9Sstevel@tonic-gate */
513*7c478bd9Sstevel@tonic-gate if (size < pgsz) {
514*7c478bd9Sstevel@tonic-gate continue;
515*7c478bd9Sstevel@tonic-gate }
516*7c478bd9Sstevel@tonic-gate
517*7c478bd9Sstevel@tonic-gate rc = pr_memcntl(Pr, (caddr_t)addr, size,
518*7c478bd9Sstevel@tonic-gate MC_HAT_ADVISE, mpss, 0, 0);
519*7c478bd9Sstevel@tonic-gate
520*7c478bd9Sstevel@tonic-gate /*
521*7c478bd9Sstevel@tonic-gate * If an error occurs on any segment, report the error here and
522*7c478bd9Sstevel@tonic-gate * then go on to try setting the page size for the remaining
523*7c478bd9Sstevel@tonic-gate * segments.
524*7c478bd9Sstevel@tonic-gate */
525*7c478bd9Sstevel@tonic-gate if (rc < 0) {
526*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: warning: set page size "
527*7c478bd9Sstevel@tonic-gate "failed (%s) for pid %d for anon segment at "
528*7c478bd9Sstevel@tonic-gate "address: %p\n", command, strerror(errno),
529*7c478bd9Sstevel@tonic-gate (int)psinfo->pr_pid, (void *)map.pr_vaddr);
530*7c478bd9Sstevel@tonic-gate }
531*7c478bd9Sstevel@tonic-gate }
532*7c478bd9Sstevel@tonic-gate
533*7c478bd9Sstevel@tonic-gate (void) close(fd);
534*7c478bd9Sstevel@tonic-gate return (0);
535*7c478bd9Sstevel@tonic-gate }
536*7c478bd9Sstevel@tonic-gate
537*7c478bd9Sstevel@tonic-gate /*
538*7c478bd9Sstevel@tonic-gate * Discover the optimal page size for the process.
539*7c478bd9Sstevel@tonic-gate * Do this by creating a 4M segment in the target process, set its pagesize
540*7c478bd9Sstevel@tonic-gate * to 0, and read the map file to discover the page size selected by the system.
541*7c478bd9Sstevel@tonic-gate */
542*7c478bd9Sstevel@tonic-gate static size_t
discover_optimal_pagesize(struct ps_prochandle * Pr,uint_t dmodel,pid_t pid)543*7c478bd9Sstevel@tonic-gate discover_optimal_pagesize(struct ps_prochandle *Pr, uint_t dmodel, pid_t pid)
544*7c478bd9Sstevel@tonic-gate {
545*7c478bd9Sstevel@tonic-gate size_t size = 0;
546*7c478bd9Sstevel@tonic-gate size_t len = pgsza[nelem - 1];
547*7c478bd9Sstevel@tonic-gate prxmap_t xmap;
548*7c478bd9Sstevel@tonic-gate caddr_t mha;
549*7c478bd9Sstevel@tonic-gate void *addr;
550*7c478bd9Sstevel@tonic-gate int fd = -1;
551*7c478bd9Sstevel@tonic-gate char path[PATH_MAX];
552*7c478bd9Sstevel@tonic-gate
553*7c478bd9Sstevel@tonic-gate (void) snprintf(path, PATH_MAX, "/proc/%d/xmap", (int)pid);
554*7c478bd9Sstevel@tonic-gate if ((fd = open(path, O_RDONLY)) < 0)
555*7c478bd9Sstevel@tonic-gate return (size);
556*7c478bd9Sstevel@tonic-gate
557*7c478bd9Sstevel@tonic-gate if ((addr = pr_mmap(Pr, (void *)len, len, PROT_READ | PROT_WRITE,
558*7c478bd9Sstevel@tonic-gate MAP_PRIVATE | MAP_ANON | MAP_ALIGN, -1, 0)) == MAP_FAILED) {
559*7c478bd9Sstevel@tonic-gate goto err;
560*7c478bd9Sstevel@tonic-gate }
561*7c478bd9Sstevel@tonic-gate
562*7c478bd9Sstevel@tonic-gate mha = setup_mha(MHA_MAPSIZE_VA, 0, dmodel);
563*7c478bd9Sstevel@tonic-gate if (pr_memcntl(Pr, addr, len, MC_HAT_ADVISE, mha, 0, 0) < 0) {
564*7c478bd9Sstevel@tonic-gate goto err;
565*7c478bd9Sstevel@tonic-gate }
566*7c478bd9Sstevel@tonic-gate
567*7c478bd9Sstevel@tonic-gate /*
568*7c478bd9Sstevel@tonic-gate * Touch a page in the segment so the hat mapping gets created.
569*7c478bd9Sstevel@tonic-gate */
570*7c478bd9Sstevel@tonic-gate (void) Pwrite(Pr, &len, sizeof (len), (uintptr_t)addr);
571*7c478bd9Sstevel@tonic-gate
572*7c478bd9Sstevel@tonic-gate /*
573*7c478bd9Sstevel@tonic-gate * Read through the address map looking for our segment.
574*7c478bd9Sstevel@tonic-gate */
575*7c478bd9Sstevel@tonic-gate
576*7c478bd9Sstevel@tonic-gate while (read(fd, &xmap, sizeof (xmap)) == sizeof (xmap)) {
577*7c478bd9Sstevel@tonic-gate if (xmap.pr_vaddr == (uintptr_t)addr)
578*7c478bd9Sstevel@tonic-gate break;
579*7c478bd9Sstevel@tonic-gate }
580*7c478bd9Sstevel@tonic-gate if (xmap.pr_vaddr != (uintptr_t)addr)
581*7c478bd9Sstevel@tonic-gate goto err;
582*7c478bd9Sstevel@tonic-gate
583*7c478bd9Sstevel@tonic-gate size = xmap.pr_hatpagesize;
584*7c478bd9Sstevel@tonic-gate
585*7c478bd9Sstevel@tonic-gate err:
586*7c478bd9Sstevel@tonic-gate if (addr != MAP_FAILED) {
587*7c478bd9Sstevel@tonic-gate if (pr_munmap(Pr, addr, len) == -1) {
588*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
589*7c478bd9Sstevel@tonic-gate "%s: couldn't delete segment at %p\n",
590*7c478bd9Sstevel@tonic-gate command, addr);
591*7c478bd9Sstevel@tonic-gate }
592*7c478bd9Sstevel@tonic-gate }
593*7c478bd9Sstevel@tonic-gate if (fd != -1)
594*7c478bd9Sstevel@tonic-gate (void) close(fd);
595*7c478bd9Sstevel@tonic-gate
596*7c478bd9Sstevel@tonic-gate return (size);
597*7c478bd9Sstevel@tonic-gate }
598*7c478bd9Sstevel@tonic-gate
599*7c478bd9Sstevel@tonic-gate static struct memcntl_mha gmha;
600*7c478bd9Sstevel@tonic-gate #ifdef _LP64
601*7c478bd9Sstevel@tonic-gate static struct memcntl_mha32 gmha32;
602*7c478bd9Sstevel@tonic-gate #endif
603*7c478bd9Sstevel@tonic-gate
604*7c478bd9Sstevel@tonic-gate static caddr_t
605*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
setup_mha(uint_t command,size_t pagesize,int dmodel)606*7c478bd9Sstevel@tonic-gate setup_mha(uint_t command, size_t pagesize, int dmodel)
607*7c478bd9Sstevel@tonic-gate {
608*7c478bd9Sstevel@tonic-gate #ifdef _LP64
609*7c478bd9Sstevel@tonic-gate if (dmodel == PR_MODEL_ILP32) {
610*7c478bd9Sstevel@tonic-gate gmha32.mha_cmd = command;
611*7c478bd9Sstevel@tonic-gate gmha32.mha_flags = 0;
612*7c478bd9Sstevel@tonic-gate gmha32.mha_pagesize = pagesize;
613*7c478bd9Sstevel@tonic-gate return ((caddr_t)&gmha32);
614*7c478bd9Sstevel@tonic-gate }
615*7c478bd9Sstevel@tonic-gate #endif
616*7c478bd9Sstevel@tonic-gate gmha.mha_cmd = command;
617*7c478bd9Sstevel@tonic-gate gmha.mha_flags = 0;
618*7c478bd9Sstevel@tonic-gate gmha.mha_pagesize = pagesize;
619*7c478bd9Sstevel@tonic-gate return ((caddr_t)&gmha);
620*7c478bd9Sstevel@tonic-gate }
621