xref: /titanic_50/usr/src/lib/libproc/common/Pidle.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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 2005 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 <stdlib.h>
30*7c478bd9Sstevel@tonic-gate #include <libelf.h>
31*7c478bd9Sstevel@tonic-gate #include <libgen.h>
32*7c478bd9Sstevel@tonic-gate #include <string.h>
33*7c478bd9Sstevel@tonic-gate #include <strings.h>
34*7c478bd9Sstevel@tonic-gate #include <errno.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate #include "Pcontrol.h"
38*7c478bd9Sstevel@tonic-gate 
39*7c478bd9Sstevel@tonic-gate static ssize_t
40*7c478bd9Sstevel@tonic-gate Pread_idle(struct ps_prochandle *P, void *buf, size_t n, uintptr_t addr)
41*7c478bd9Sstevel@tonic-gate {
42*7c478bd9Sstevel@tonic-gate 	size_t resid = n;
43*7c478bd9Sstevel@tonic-gate 
44*7c478bd9Sstevel@tonic-gate 	while (resid > 0) {
45*7c478bd9Sstevel@tonic-gate 		map_info_t *mp;
46*7c478bd9Sstevel@tonic-gate 		uintptr_t mapoff;
47*7c478bd9Sstevel@tonic-gate 		ssize_t len;
48*7c478bd9Sstevel@tonic-gate 		off64_t off;
49*7c478bd9Sstevel@tonic-gate 
50*7c478bd9Sstevel@tonic-gate 		if ((mp = Paddr2mptr(P, addr)) == NULL)
51*7c478bd9Sstevel@tonic-gate 			break;
52*7c478bd9Sstevel@tonic-gate 
53*7c478bd9Sstevel@tonic-gate 		mapoff = addr - mp->map_pmap.pr_vaddr;
54*7c478bd9Sstevel@tonic-gate 		len = MIN(resid, mp->map_pmap.pr_size - mapoff);
55*7c478bd9Sstevel@tonic-gate 		off = mp->map_offset + mapoff;
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate 		if ((len = pread64(P->asfd, buf, len, off)) <= 0)
58*7c478bd9Sstevel@tonic-gate 			break;
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate 		resid -= len;
61*7c478bd9Sstevel@tonic-gate 		addr += len;
62*7c478bd9Sstevel@tonic-gate 		buf = (char *)buf + len;
63*7c478bd9Sstevel@tonic-gate 	}
64*7c478bd9Sstevel@tonic-gate 
65*7c478bd9Sstevel@tonic-gate 	return (n - resid);
66*7c478bd9Sstevel@tonic-gate }
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
69*7c478bd9Sstevel@tonic-gate static ssize_t
70*7c478bd9Sstevel@tonic-gate Pwrite_idle(struct ps_prochandle *P, const void *buf, size_t n, uintptr_t addr)
71*7c478bd9Sstevel@tonic-gate {
72*7c478bd9Sstevel@tonic-gate 	errno = EIO;
73*7c478bd9Sstevel@tonic-gate 	return (-1);
74*7c478bd9Sstevel@tonic-gate }
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate static const ps_rwops_t P_idle_ops = {
77*7c478bd9Sstevel@tonic-gate 	Pread_idle,
78*7c478bd9Sstevel@tonic-gate 	Pwrite_idle
79*7c478bd9Sstevel@tonic-gate };
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate static int
82*7c478bd9Sstevel@tonic-gate idle_add_mapping(struct ps_prochandle *P, GElf_Phdr *php, file_info_t *fp)
83*7c478bd9Sstevel@tonic-gate {
84*7c478bd9Sstevel@tonic-gate 	prmap_t pmap;
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate 	dprintf("mapping base %llx filesz %llu memsz %llu offset %llu\n",
87*7c478bd9Sstevel@tonic-gate 	    (u_longlong_t)php->p_vaddr, (u_longlong_t)php->p_filesz,
88*7c478bd9Sstevel@tonic-gate 	    (u_longlong_t)php->p_memsz, (u_longlong_t)php->p_offset);
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate 	pmap.pr_vaddr = (uintptr_t)php->p_vaddr;
91*7c478bd9Sstevel@tonic-gate 	pmap.pr_size = php->p_filesz;
92*7c478bd9Sstevel@tonic-gate 	(void) strncpy(pmap.pr_mapname, fp->file_pname,
93*7c478bd9Sstevel@tonic-gate 	    sizeof (pmap.pr_mapname));
94*7c478bd9Sstevel@tonic-gate 	pmap.pr_offset = php->p_offset;
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate 	pmap.pr_mflags = 0;
97*7c478bd9Sstevel@tonic-gate 	if (php->p_flags & PF_R)
98*7c478bd9Sstevel@tonic-gate 		pmap.pr_mflags |= MA_READ;
99*7c478bd9Sstevel@tonic-gate 	if (php->p_flags & PF_W)
100*7c478bd9Sstevel@tonic-gate 		pmap.pr_mflags |= MA_WRITE;
101*7c478bd9Sstevel@tonic-gate 	if (php->p_flags & PF_X)
102*7c478bd9Sstevel@tonic-gate 		pmap.pr_mflags |= MA_EXEC;
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate 	pmap.pr_pagesize = 0;
105*7c478bd9Sstevel@tonic-gate 	pmap.pr_shmid = -1;
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate 	return (Padd_mapping(P, php->p_offset, fp, &pmap));
108*7c478bd9Sstevel@tonic-gate }
109*7c478bd9Sstevel@tonic-gate 
110*7c478bd9Sstevel@tonic-gate struct ps_prochandle *
111*7c478bd9Sstevel@tonic-gate Pgrab_file(const char *fname, int *perr)
112*7c478bd9Sstevel@tonic-gate {
113*7c478bd9Sstevel@tonic-gate 	struct ps_prochandle *P = NULL;
114*7c478bd9Sstevel@tonic-gate 	GElf_Ehdr ehdr;
115*7c478bd9Sstevel@tonic-gate 	Elf *elf = NULL;
116*7c478bd9Sstevel@tonic-gate 	file_info_t *fp = NULL;
117*7c478bd9Sstevel@tonic-gate 	int fd;
118*7c478bd9Sstevel@tonic-gate 	int i;
119*7c478bd9Sstevel@tonic-gate 
120*7c478bd9Sstevel@tonic-gate 	if ((fd = open64(fname, O_RDONLY)) < 0) {
121*7c478bd9Sstevel@tonic-gate 		dprintf("couldn't open file");
122*7c478bd9Sstevel@tonic-gate 		*perr = (errno == ENOENT) ? G_NOEXEC : G_STRANGE;
123*7c478bd9Sstevel@tonic-gate 		return (NULL);
124*7c478bd9Sstevel@tonic-gate 	}
125*7c478bd9Sstevel@tonic-gate 
126*7c478bd9Sstevel@tonic-gate 	if (elf_version(EV_CURRENT) == EV_NONE) {
127*7c478bd9Sstevel@tonic-gate 		dprintf("libproc ELF version is more recent than libelf");
128*7c478bd9Sstevel@tonic-gate 		*perr = G_ELF;
129*7c478bd9Sstevel@tonic-gate 		goto err;
130*7c478bd9Sstevel@tonic-gate 	}
131*7c478bd9Sstevel@tonic-gate 
132*7c478bd9Sstevel@tonic-gate 	if ((P = calloc(1, sizeof (struct ps_prochandle))) == NULL) {
133*7c478bd9Sstevel@tonic-gate 		*perr = G_STRANGE;
134*7c478bd9Sstevel@tonic-gate 		goto err;
135*7c478bd9Sstevel@tonic-gate 	}
136*7c478bd9Sstevel@tonic-gate 
137*7c478bd9Sstevel@tonic-gate 	(void) mutex_init(&P->proc_lock, USYNC_THREAD, NULL);
138*7c478bd9Sstevel@tonic-gate 	P->state = PS_IDLE;
139*7c478bd9Sstevel@tonic-gate 	P->pid = (pid_t)-1;
140*7c478bd9Sstevel@tonic-gate 	P->asfd = fd;
141*7c478bd9Sstevel@tonic-gate 	P->ctlfd = -1;
142*7c478bd9Sstevel@tonic-gate 	P->statfd = -1;
143*7c478bd9Sstevel@tonic-gate 	P->agentctlfd = -1;
144*7c478bd9Sstevel@tonic-gate 	P->agentstatfd = -1;
145*7c478bd9Sstevel@tonic-gate 	P->info_valid = -1;
146*7c478bd9Sstevel@tonic-gate 	P->ops = &P_idle_ops;
147*7c478bd9Sstevel@tonic-gate 	Pinitsym(P);
148*7c478bd9Sstevel@tonic-gate 
149*7c478bd9Sstevel@tonic-gate 	if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
150*7c478bd9Sstevel@tonic-gate 		*perr = G_ELF;
151*7c478bd9Sstevel@tonic-gate 		return (NULL);
152*7c478bd9Sstevel@tonic-gate 	}
153*7c478bd9Sstevel@tonic-gate 
154*7c478bd9Sstevel@tonic-gate 	/*
155*7c478bd9Sstevel@tonic-gate 	 * Construct a file_info_t that corresponds to this file.
156*7c478bd9Sstevel@tonic-gate 	 */
157*7c478bd9Sstevel@tonic-gate 	if ((fp = calloc(1, sizeof (file_info_t))) == NULL) {
158*7c478bd9Sstevel@tonic-gate 		*perr = G_STRANGE;
159*7c478bd9Sstevel@tonic-gate 		goto err;
160*7c478bd9Sstevel@tonic-gate 	}
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate 	if ((fp->file_lo = calloc(1, sizeof (rd_loadobj_t))) == NULL) {
163*7c478bd9Sstevel@tonic-gate 		*perr = G_STRANGE;
164*7c478bd9Sstevel@tonic-gate 		goto err;
165*7c478bd9Sstevel@tonic-gate 	}
166*7c478bd9Sstevel@tonic-gate 
167*7c478bd9Sstevel@tonic-gate 	if (*fname == '/') {
168*7c478bd9Sstevel@tonic-gate 		(void) strncpy(fp->file_pname, fname, sizeof (fp->file_pname));
169*7c478bd9Sstevel@tonic-gate 	} else {
170*7c478bd9Sstevel@tonic-gate 		size_t sz;
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate 		if (getcwd(fp->file_pname, sizeof (fp->file_pname) - 1) ==
173*7c478bd9Sstevel@tonic-gate 		    NULL) {
174*7c478bd9Sstevel@tonic-gate 			*perr = G_STRANGE;
175*7c478bd9Sstevel@tonic-gate 			goto err;
176*7c478bd9Sstevel@tonic-gate 		}
177*7c478bd9Sstevel@tonic-gate 
178*7c478bd9Sstevel@tonic-gate 		sz = strlen(fp->file_pname);
179*7c478bd9Sstevel@tonic-gate 		(void) snprintf(&fp->file_pname[sz],
180*7c478bd9Sstevel@tonic-gate 		    sizeof (fp->file_pname) - sz, "/%s", fname);
181*7c478bd9Sstevel@tonic-gate 	}
182*7c478bd9Sstevel@tonic-gate 
183*7c478bd9Sstevel@tonic-gate 	fp->file_fd = fd;
184*7c478bd9Sstevel@tonic-gate 	fp->file_lo->rl_lmident = LM_ID_BASE;
185*7c478bd9Sstevel@tonic-gate 	fp->file_lname = strdup(fp->file_pname);
186*7c478bd9Sstevel@tonic-gate 	fp->file_lbase = basename(fp->file_lname);
187*7c478bd9Sstevel@tonic-gate 
188*7c478bd9Sstevel@tonic-gate 	P->execname = strdup(fp->file_pname);
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate 	P->num_files++;
191*7c478bd9Sstevel@tonic-gate 	list_link(fp, &P->file_head);
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate 	if (gelf_getehdr(elf, &ehdr) == NULL) {
194*7c478bd9Sstevel@tonic-gate 		*perr = G_STRANGE;
195*7c478bd9Sstevel@tonic-gate 		goto err;
196*7c478bd9Sstevel@tonic-gate 	}
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate 	dprintf("Pgrab_file: ehdr.e_phnum = %d\n", ehdr.e_phnum);
199*7c478bd9Sstevel@tonic-gate 
200*7c478bd9Sstevel@tonic-gate 	/*
201*7c478bd9Sstevel@tonic-gate 	 * Sift through the program headers making the relevant maps.
202*7c478bd9Sstevel@tonic-gate 	 */
203*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < ehdr.e_phnum; i++) {
204*7c478bd9Sstevel@tonic-gate 		GElf_Phdr phdr, *php;
205*7c478bd9Sstevel@tonic-gate 
206*7c478bd9Sstevel@tonic-gate 		if ((php = gelf_getphdr(elf, i, &phdr)) == NULL) {
207*7c478bd9Sstevel@tonic-gate 			*perr = G_STRANGE;
208*7c478bd9Sstevel@tonic-gate 			goto err;
209*7c478bd9Sstevel@tonic-gate 		}
210*7c478bd9Sstevel@tonic-gate 
211*7c478bd9Sstevel@tonic-gate 		if (php->p_type != PT_LOAD)
212*7c478bd9Sstevel@tonic-gate 			continue;
213*7c478bd9Sstevel@tonic-gate 
214*7c478bd9Sstevel@tonic-gate 		if (idle_add_mapping(P, php, fp) != 0) {
215*7c478bd9Sstevel@tonic-gate 			*perr = G_STRANGE;
216*7c478bd9Sstevel@tonic-gate 			goto err;
217*7c478bd9Sstevel@tonic-gate 		}
218*7c478bd9Sstevel@tonic-gate 	}
219*7c478bd9Sstevel@tonic-gate 	Psort_mappings(P);
220*7c478bd9Sstevel@tonic-gate 
221*7c478bd9Sstevel@tonic-gate 	(void) elf_end(elf);
222*7c478bd9Sstevel@tonic-gate 
223*7c478bd9Sstevel@tonic-gate 	P->map_exec = fp->file_map;
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate 	P->status.pr_flags = PR_STOPPED;
226*7c478bd9Sstevel@tonic-gate 	P->status.pr_nlwp = 0;
227*7c478bd9Sstevel@tonic-gate 	P->status.pr_pid = (pid_t)-1;
228*7c478bd9Sstevel@tonic-gate 	P->status.pr_ppid = (pid_t)-1;
229*7c478bd9Sstevel@tonic-gate 	P->status.pr_pgid = (pid_t)-1;
230*7c478bd9Sstevel@tonic-gate 	P->status.pr_sid = (pid_t)-1;
231*7c478bd9Sstevel@tonic-gate 	P->status.pr_taskid = (taskid_t)-1;
232*7c478bd9Sstevel@tonic-gate 	P->status.pr_projid = (projid_t)-1;
233*7c478bd9Sstevel@tonic-gate 	switch (ehdr.e_ident[EI_CLASS]) {
234*7c478bd9Sstevel@tonic-gate 	case ELFCLASS32:
235*7c478bd9Sstevel@tonic-gate 		P->status.pr_dmodel = PR_MODEL_ILP32;
236*7c478bd9Sstevel@tonic-gate 		break;
237*7c478bd9Sstevel@tonic-gate 	case ELFCLASS64:
238*7c478bd9Sstevel@tonic-gate 		P->status.pr_dmodel = PR_MODEL_LP64;
239*7c478bd9Sstevel@tonic-gate 		break;
240*7c478bd9Sstevel@tonic-gate 	default:
241*7c478bd9Sstevel@tonic-gate 		*perr = G_FORMAT;
242*7c478bd9Sstevel@tonic-gate 		goto err;
243*7c478bd9Sstevel@tonic-gate 	}
244*7c478bd9Sstevel@tonic-gate 
245*7c478bd9Sstevel@tonic-gate 	/*
246*7c478bd9Sstevel@tonic-gate 	 * The file and map lists are complete, and will never need to be
247*7c478bd9Sstevel@tonic-gate 	 * adjusted.
248*7c478bd9Sstevel@tonic-gate 	 */
249*7c478bd9Sstevel@tonic-gate 	P->info_valid = 1;
250*7c478bd9Sstevel@tonic-gate 
251*7c478bd9Sstevel@tonic-gate 	return (P);
252*7c478bd9Sstevel@tonic-gate err:
253*7c478bd9Sstevel@tonic-gate 	(void) close(fd);
254*7c478bd9Sstevel@tonic-gate 	if (P != NULL)
255*7c478bd9Sstevel@tonic-gate 		Pfree(P);
256*7c478bd9Sstevel@tonic-gate 	if (elf != NULL)
257*7c478bd9Sstevel@tonic-gate 		(void) elf_end(elf);
258*7c478bd9Sstevel@tonic-gate 	return (NULL);
259*7c478bd9Sstevel@tonic-gate }
260