xref: /illumos-gate/usr/src/lib/libproc/common/Pidle.c (revision 7b209c2c)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <stdlib.h>
30 #include <libelf.h>
31 #include <libgen.h>
32 #include <string.h>
33 #include <strings.h>
34 #include <errno.h>
35 #include <sys/sysmacros.h>
36 
37 #include "Pcontrol.h"
38 
39 static ssize_t
40 Pread_idle(struct ps_prochandle *P, void *buf, size_t n, uintptr_t addr)
41 {
42 	size_t resid = n;
43 
44 	while (resid > 0) {
45 		map_info_t *mp;
46 		uintptr_t mapoff;
47 		ssize_t len;
48 		off64_t off;
49 
50 		if ((mp = Paddr2mptr(P, addr)) == NULL)
51 			break;
52 
53 		mapoff = addr - mp->map_pmap.pr_vaddr;
54 		len = MIN(resid, mp->map_pmap.pr_size - mapoff);
55 		off = mp->map_offset + mapoff;
56 
57 		if ((len = pread64(P->asfd, buf, len, off)) <= 0)
58 			break;
59 
60 		resid -= len;
61 		addr += len;
62 		buf = (char *)buf + len;
63 	}
64 
65 	return (n - resid);
66 }
67 
68 /*ARGSUSED*/
69 static ssize_t
70 Pwrite_idle(struct ps_prochandle *P, const void *buf, size_t n, uintptr_t addr)
71 {
72 	errno = EIO;
73 	return (-1);
74 }
75 
76 static const ps_rwops_t P_idle_ops = {
77 	Pread_idle,
78 	Pwrite_idle
79 };
80 
81 static int
82 idle_add_mapping(struct ps_prochandle *P, GElf_Phdr *php, file_info_t *fp)
83 {
84 	prmap_t pmap;
85 
86 	dprintf("mapping base %llx filesz %llu memsz %llu offset %llu\n",
87 	    (u_longlong_t)php->p_vaddr, (u_longlong_t)php->p_filesz,
88 	    (u_longlong_t)php->p_memsz, (u_longlong_t)php->p_offset);
89 
90 	pmap.pr_vaddr = (uintptr_t)php->p_vaddr;
91 	pmap.pr_size = php->p_filesz;
92 	(void) strncpy(pmap.pr_mapname, fp->file_pname,
93 	    sizeof (pmap.pr_mapname));
94 	pmap.pr_offset = php->p_offset;
95 
96 	pmap.pr_mflags = 0;
97 	if (php->p_flags & PF_R)
98 		pmap.pr_mflags |= MA_READ;
99 	if (php->p_flags & PF_W)
100 		pmap.pr_mflags |= MA_WRITE;
101 	if (php->p_flags & PF_X)
102 		pmap.pr_mflags |= MA_EXEC;
103 
104 	pmap.pr_pagesize = 0;
105 	pmap.pr_shmid = -1;
106 
107 	return (Padd_mapping(P, php->p_offset, fp, &pmap));
108 }
109 
110 struct ps_prochandle *
111 Pgrab_file(const char *fname, int *perr)
112 {
113 	struct ps_prochandle *P = NULL;
114 	GElf_Ehdr ehdr;
115 	Elf *elf = NULL;
116 	size_t phnum;
117 	file_info_t *fp = NULL;
118 	int fd;
119 	int i;
120 
121 	if ((fd = open64(fname, O_RDONLY)) < 0) {
122 		dprintf("couldn't open file");
123 		*perr = (errno == ENOENT) ? G_NOEXEC : G_STRANGE;
124 		return (NULL);
125 	}
126 
127 	if (elf_version(EV_CURRENT) == EV_NONE) {
128 		dprintf("libproc ELF version is more recent than libelf");
129 		*perr = G_ELF;
130 		goto err;
131 	}
132 
133 	if ((P = calloc(1, sizeof (struct ps_prochandle))) == NULL) {
134 		*perr = G_STRANGE;
135 		goto err;
136 	}
137 
138 	(void) mutex_init(&P->proc_lock, USYNC_THREAD, NULL);
139 	P->state = PS_IDLE;
140 	P->pid = (pid_t)-1;
141 	P->asfd = fd;
142 	P->ctlfd = -1;
143 	P->statfd = -1;
144 	P->agentctlfd = -1;
145 	P->agentstatfd = -1;
146 	P->info_valid = -1;
147 	P->ops = &P_idle_ops;
148 	Pinitsym(P);
149 
150 	if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
151 		*perr = G_ELF;
152 		return (NULL);
153 	}
154 
155 	/*
156 	 * Construct a file_info_t that corresponds to this file.
157 	 */
158 	if ((fp = calloc(1, sizeof (file_info_t))) == NULL) {
159 		*perr = G_STRANGE;
160 		goto err;
161 	}
162 
163 	if ((fp->file_lo = calloc(1, sizeof (rd_loadobj_t))) == NULL) {
164 		*perr = G_STRANGE;
165 		goto err;
166 	}
167 
168 	if (*fname == '/') {
169 		(void) strncpy(fp->file_pname, fname, sizeof (fp->file_pname));
170 	} else {
171 		size_t sz;
172 
173 		if (getcwd(fp->file_pname, sizeof (fp->file_pname) - 1) ==
174 		    NULL) {
175 			*perr = G_STRANGE;
176 			goto err;
177 		}
178 
179 		sz = strlen(fp->file_pname);
180 		(void) snprintf(&fp->file_pname[sz],
181 		    sizeof (fp->file_pname) - sz, "/%s", fname);
182 	}
183 
184 	fp->file_fd = fd;
185 	fp->file_lo->rl_lmident = LM_ID_BASE;
186 	fp->file_lname = strdup(fp->file_pname);
187 	fp->file_lbase = basename(fp->file_lname);
188 
189 	P->execname = strdup(fp->file_pname);
190 
191 	P->num_files++;
192 	list_link(fp, &P->file_head);
193 
194 	if (gelf_getehdr(elf, &ehdr) == NULL) {
195 		*perr = G_STRANGE;
196 		goto err;
197 	}
198 
199 	if (elf_getphnum(elf, &phnum) == 0) {
200 		*perr = G_STRANGE;
201 		goto err;
202 	}
203 
204 	dprintf("Pgrab_file: program header count = %lu\n", (ulong_t)phnum);
205 
206 	/*
207 	 * Sift through the program headers making the relevant maps.
208 	 */
209 	for (i = 0; i < phnum; i++) {
210 		GElf_Phdr phdr, *php;
211 
212 		if ((php = gelf_getphdr(elf, i, &phdr)) == NULL) {
213 			*perr = G_STRANGE;
214 			goto err;
215 		}
216 
217 		if (php->p_type != PT_LOAD)
218 			continue;
219 
220 		if (idle_add_mapping(P, php, fp) != 0) {
221 			*perr = G_STRANGE;
222 			goto err;
223 		}
224 	}
225 	Psort_mappings(P);
226 
227 	(void) elf_end(elf);
228 
229 	P->map_exec = fp->file_map;
230 
231 	P->status.pr_flags = PR_STOPPED;
232 	P->status.pr_nlwp = 0;
233 	P->status.pr_pid = (pid_t)-1;
234 	P->status.pr_ppid = (pid_t)-1;
235 	P->status.pr_pgid = (pid_t)-1;
236 	P->status.pr_sid = (pid_t)-1;
237 	P->status.pr_taskid = (taskid_t)-1;
238 	P->status.pr_projid = (projid_t)-1;
239 	switch (ehdr.e_ident[EI_CLASS]) {
240 	case ELFCLASS32:
241 		P->status.pr_dmodel = PR_MODEL_ILP32;
242 		break;
243 	case ELFCLASS64:
244 		P->status.pr_dmodel = PR_MODEL_LP64;
245 		break;
246 	default:
247 		*perr = G_FORMAT;
248 		goto err;
249 	}
250 
251 	/*
252 	 * The file and map lists are complete, and will never need to be
253 	 * adjusted.
254 	 */
255 	P->info_valid = 1;
256 
257 	return (P);
258 err:
259 	(void) close(fd);
260 	if (P != NULL)
261 		Pfree(P);
262 	if (elf != NULL)
263 		(void) elf_end(elf);
264 	return (NULL);
265 }
266