xref: /titanic_51/usr/src/lib/libproc/common/Pidle.c (revision fa9e4066f08beec538e775443c5be79dd423fcab)
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 	file_info_t *fp = NULL;
117 	int fd;
118 	int i;
119 
120 	if ((fd = open64(fname, O_RDONLY)) < 0) {
121 		dprintf("couldn't open file");
122 		*perr = (errno == ENOENT) ? G_NOEXEC : G_STRANGE;
123 		return (NULL);
124 	}
125 
126 	if (elf_version(EV_CURRENT) == EV_NONE) {
127 		dprintf("libproc ELF version is more recent than libelf");
128 		*perr = G_ELF;
129 		goto err;
130 	}
131 
132 	if ((P = calloc(1, sizeof (struct ps_prochandle))) == NULL) {
133 		*perr = G_STRANGE;
134 		goto err;
135 	}
136 
137 	(void) mutex_init(&P->proc_lock, USYNC_THREAD, NULL);
138 	P->state = PS_IDLE;
139 	P->pid = (pid_t)-1;
140 	P->asfd = fd;
141 	P->ctlfd = -1;
142 	P->statfd = -1;
143 	P->agentctlfd = -1;
144 	P->agentstatfd = -1;
145 	P->info_valid = -1;
146 	P->ops = &P_idle_ops;
147 	Pinitsym(P);
148 
149 	if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
150 		*perr = G_ELF;
151 		return (NULL);
152 	}
153 
154 	/*
155 	 * Construct a file_info_t that corresponds to this file.
156 	 */
157 	if ((fp = calloc(1, sizeof (file_info_t))) == NULL) {
158 		*perr = G_STRANGE;
159 		goto err;
160 	}
161 
162 	if ((fp->file_lo = calloc(1, sizeof (rd_loadobj_t))) == NULL) {
163 		*perr = G_STRANGE;
164 		goto err;
165 	}
166 
167 	if (*fname == '/') {
168 		(void) strncpy(fp->file_pname, fname, sizeof (fp->file_pname));
169 	} else {
170 		size_t sz;
171 
172 		if (getcwd(fp->file_pname, sizeof (fp->file_pname) - 1) ==
173 		    NULL) {
174 			*perr = G_STRANGE;
175 			goto err;
176 		}
177 
178 		sz = strlen(fp->file_pname);
179 		(void) snprintf(&fp->file_pname[sz],
180 		    sizeof (fp->file_pname) - sz, "/%s", fname);
181 	}
182 
183 	fp->file_fd = fd;
184 	fp->file_lo->rl_lmident = LM_ID_BASE;
185 	fp->file_lname = strdup(fp->file_pname);
186 	fp->file_lbase = basename(fp->file_lname);
187 
188 	P->execname = strdup(fp->file_pname);
189 
190 	P->num_files++;
191 	list_link(fp, &P->file_head);
192 
193 	if (gelf_getehdr(elf, &ehdr) == NULL) {
194 		*perr = G_STRANGE;
195 		goto err;
196 	}
197 
198 	dprintf("Pgrab_file: ehdr.e_phnum = %d\n", ehdr.e_phnum);
199 
200 	/*
201 	 * Sift through the program headers making the relevant maps.
202 	 */
203 	for (i = 0; i < ehdr.e_phnum; i++) {
204 		GElf_Phdr phdr, *php;
205 
206 		if ((php = gelf_getphdr(elf, i, &phdr)) == NULL) {
207 			*perr = G_STRANGE;
208 			goto err;
209 		}
210 
211 		if (php->p_type != PT_LOAD)
212 			continue;
213 
214 		if (idle_add_mapping(P, php, fp) != 0) {
215 			*perr = G_STRANGE;
216 			goto err;
217 		}
218 	}
219 	Psort_mappings(P);
220 
221 	(void) elf_end(elf);
222 
223 	P->map_exec = fp->file_map;
224 
225 	P->status.pr_flags = PR_STOPPED;
226 	P->status.pr_nlwp = 0;
227 	P->status.pr_pid = (pid_t)-1;
228 	P->status.pr_ppid = (pid_t)-1;
229 	P->status.pr_pgid = (pid_t)-1;
230 	P->status.pr_sid = (pid_t)-1;
231 	P->status.pr_taskid = (taskid_t)-1;
232 	P->status.pr_projid = (projid_t)-1;
233 	switch (ehdr.e_ident[EI_CLASS]) {
234 	case ELFCLASS32:
235 		P->status.pr_dmodel = PR_MODEL_ILP32;
236 		break;
237 	case ELFCLASS64:
238 		P->status.pr_dmodel = PR_MODEL_LP64;
239 		break;
240 	default:
241 		*perr = G_FORMAT;
242 		goto err;
243 	}
244 
245 	/*
246 	 * The file and map lists are complete, and will never need to be
247 	 * adjusted.
248 	 */
249 	P->info_valid = 1;
250 
251 	return (P);
252 err:
253 	(void) close(fd);
254 	if (P != NULL)
255 		Pfree(P);
256 	if (elf != NULL)
257 		(void) elf_end(elf);
258 	return (NULL);
259 }
260