xref: /illumos-gate/usr/src/cmd/sgs/demo_rdb/common/ps.c (revision 43449cdcd0600512dd862537f2cf014140dd0844)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <sys/uio.h>
30 #include <fcntl.h>
31 #include <string.h>
32 #include <errno.h>
33 #include <sys/types.h>
34 #include <sys/signal.h>
35 #include <sys/fault.h>
36 #include <sys/syscall.h>
37 #include <procfs.h>
38 #include <sys/auxv.h>
39 #include <sys/stat.h>
40 #include <sys/mman.h>
41 #include <libelf.h>
42 #include <sys/param.h>
43 #include <sys/machelf.h>
44 #include <stdarg.h>
45 
46 #include <proc_service.h>
47 
48 #include "rdb.h"
49 #include "disasm.h"
50 
51 #if	!defined(_LP64)
52 static void
53 gelf_sym_to_elf32(GElf_Sym *src, Elf32_Sym *dst)
54 {
55 	dst->st_name	= src->st_name;
56 	dst->st_value	= src->st_value;
57 	dst->st_size	= src->st_size;
58 	dst->st_info	= ELF32_ST_INFO(GELF_ST_BIND(src->st_info),
59 	    GELF_ST_TYPE(src->st_info));
60 	dst->st_other	= src->st_other;
61 	dst->st_shndx	= src->st_shndx;
62 }
63 #endif
64 
65 #define	PROCSIZE	20
66 
67 static void
68 get_ldbase(struct ps_prochandle *procp)
69 {
70 	int		pauxvfd;
71 	char		pname[PROCSIZE];
72 	struct stat	stbuf;
73 	void		*auxvptr, *auxvtail;
74 	auxv_t		*auxvp;
75 	uint_t		entsize;
76 
77 	(void) snprintf(pname, PROCSIZE, "/proc/%d/auxv",
78 	    EC_SWORD(procp->pp_pid));
79 	if ((pauxvfd = open(pname, O_RDONLY)) == -1)
80 		perr("open auxv");
81 
82 	if (fstat(pauxvfd, &stbuf) == -1)
83 		perr("stat auxv");
84 
85 	auxvptr = malloc(stbuf.st_size);
86 	if (read(pauxvfd, auxvptr, stbuf.st_size) == -1)
87 		perr("gldb: reading auxv");
88 
89 	(void) close(pauxvfd);
90 
91 	procp->pp_auxvp = auxvptr;
92 	auxvtail = (void *)((uintptr_t)auxvptr + stbuf.st_size);
93 
94 #if defined(_LP64)
95 	if (procp->pp_dmodel == PR_MODEL_ILP32)
96 		entsize = sizeof (auxv32_t);
97 	else
98 #endif
99 		entsize = sizeof (auxv_t);
100 
101 	while (auxvptr < auxvtail) {
102 		auxvp = auxvptr;
103 		if (auxvp->a_type == AT_BASE) {
104 #if defined(_LP64)
105 			if (procp->pp_dmodel == PR_MODEL_ILP32)
106 				procp->pp_ldsobase =
107 				    ((uintptr_t)((auxv32_t *)auxvp)->
108 				    a_un.a_val);
109 			else
110 #endif
111 				procp->pp_ldsobase =  auxvp->a_un.a_val;
112 		} else if (auxvp->a_type == AT_PHDR) {
113 #if defined(_LP64)
114 			if (procp->pp_dmodel == PR_MODEL_ILP32)
115 				procp->pp_execphdr =
116 				    ((uintptr_t)((auxv32_t *)auxvp)->
117 				    a_un.a_val);
118 			else
119 #endif
120 				procp->pp_execphdr =  auxvp->a_un.a_val;
121 		}
122 		auxvptr = (void *)((uintptr_t)auxvptr + entsize);
123 	}
124 }
125 
126 retc_t
127 ps_init(int pctlfd, int pstatusfd, pid_t pid, struct ps_prochandle *procp)
128 {
129 	rd_notify_t	rd_notify;
130 	char		procname[PROCSIZE];
131 	long		oper, pflags;
132 	struct iovec	piov[2];
133 
134 	procp->pp_pid = pid;
135 	procp->pp_ctlfd = pctlfd;
136 	procp->pp_statusfd = pstatusfd;
137 
138 	(void) snprintf(procname, PROCSIZE, "/proc/%d/map",
139 	    EC_SWORD(procp->pp_pid));
140 	if ((procp->pp_mapfd = open(procname, O_RDONLY)) == -1)
141 		perr("psi: open of /proc/dpid/map failed");
142 
143 	(void) snprintf(procname, PROCSIZE, "/proc/%d/as",
144 	    EC_SWORD(procp->pp_pid));
145 	if ((procp->pp_asfd = open(procname, O_RDWR)) == -1)
146 		perr("psi: open of /proc/dpid/as failed");
147 
148 	if (ps_pdmodel(procp, &procp->pp_dmodel) != PS_OK)
149 		perr("psi: data model");
150 
151 #if	!defined(_LP64)
152 	if (procp->pp_dmodel == PR_MODEL_LP64)
153 		perr("psi:  run 64-bit rdb to debug a 64-bit process");
154 #endif
155 	get_ldbase(procp);
156 
157 	(void) load_map(procp, (caddr_t)procp->pp_ldsobase,
158 	    &(procp->pp_ldsomap));
159 	procp->pp_ldsomap.mi_addr += procp->pp_ldsobase;
160 	procp->pp_ldsomap.mi_end += procp->pp_ldsobase;
161 	procp->pp_ldsomap.mi_name = "<procfs: interp>";
162 
163 	(void) load_map(procp, (caddr_t)procp->pp_execphdr,
164 	    &(procp->pp_execmap));
165 	procp->pp_execmap.mi_name = "<procfs: exec>";
166 
167 	procp->pp_breakpoints = NULL;
168 	procp->pp_flags = FLG_PP_PACT | FLG_PP_PLTSKIP;
169 	procp->pp_lmaplist.ml_head = NULL;
170 	procp->pp_lmaplist.ml_tail = NULL;
171 	if ((procp->pp_rap = rd_new(procp)) == NULL) {
172 		(void) fprintf(stderr, "rdb: rtld_db: rd_new() call failed\n");
173 		exit(1);
174 	}
175 	(void) rd_event_enable(procp->pp_rap, 1);
176 
177 	/*
178 	 * For those architectures that increment the PC on
179 	 * a breakpoint fault we enable the PR_BPTADJ adjustments.
180 	 */
181 	oper = PCSET;
182 	pflags = PR_BPTADJ;
183 	piov[0].iov_base = (caddr_t)(&oper);
184 	piov[0].iov_len = sizeof (oper);
185 	piov[1].iov_base = (caddr_t)(&pflags);
186 	piov[1].iov_len = sizeof (pflags);
187 	if (writev(procp->pp_ctlfd, piov, 2) == -1)
188 		perr("psinit: PCSET(PR_BTPADJ)");
189 
190 	/*
191 	 * Set breakpoints for special handshakes between librtld_db.so
192 	 * and the debugger.  These include:
193 	 *	PREINIT		- before .init processing.
194 	 *	POSTINIT	- after .init processing
195 	 *	DLACTIVITY	- link_maps status has changed
196 	 */
197 	if (rd_event_addr(procp->pp_rap, RD_PREINIT, &rd_notify) == RD_OK) {
198 		if (set_breakpoint(procp, rd_notify.u.bptaddr,
199 		    FLG_BP_RDPREINIT) != RET_OK)
200 			(void) fprintf(stderr,
201 			    "psi: failed to set BP for preinit at: 0x%lx\n",
202 			    rd_notify.u.bptaddr);
203 	} else
204 		(void) fprintf(stderr, "psi: no event registered for "
205 		    "preinit\n");
206 
207 	if (rd_event_addr(procp->pp_rap, RD_POSTINIT, &rd_notify) == RD_OK) {
208 		if (set_breakpoint(procp, rd_notify.u.bptaddr,
209 		    FLG_BP_RDPOSTINIT) != RET_OK)
210 			(void) fprintf(stderr,
211 			    "psi: failed to set BP for postinit at: 0x%lx\n",
212 			    rd_notify.u.bptaddr);
213 	} else
214 		(void) fprintf(stderr, "psi: no event registered for "
215 		    "postinit\n");
216 
217 	if (rd_event_addr(procp->pp_rap, RD_DLACTIVITY, &rd_notify) == RD_OK) {
218 		if (set_breakpoint(procp, rd_notify.u.bptaddr,
219 		    FLG_BP_RDDLACT) != RET_OK)
220 			(void) fprintf(stderr,
221 			    "psi: failed to set BP for dlact at: 0x%lx\n",
222 			    rd_notify.u.bptaddr);
223 	} else
224 		(void) fprintf(stderr, "psi: no event registered for dlact\n");
225 
226 	return (RET_OK);
227 }
228 
229 retc_t
230 ps_close(struct ps_prochandle *ph)
231 {
232 	(void) delete_all_breakpoints(ph);
233 
234 	if (ph->pp_auxvp)
235 		free(ph->pp_auxvp);
236 	free_linkmaps(ph);
237 	return (RET_OK);
238 }
239 
240 ps_err_e
241 ps_pauxv(struct ps_prochandle *ph, const auxv_t **auxvp)
242 {
243 	*auxvp = ph->pp_auxvp;
244 	return (PS_OK);
245 }
246 
247 ps_err_e
248 ps_pdmodel(struct ps_prochandle *ph, int *dm)
249 {
250 	pstatus_t	pstatus;
251 
252 	if (pread(ph->pp_statusfd, &pstatus, sizeof (pstatus), 0) == -1)
253 		return (PS_ERR);
254 
255 	*dm = (int)pstatus.pr_dmodel;
256 	return (PS_OK);
257 }
258 
259 ps_err_e
260 ps_pread(struct ps_prochandle *ph, psaddr_t addr, void *buf, size_t size)
261 {
262 	if (pread(ph->pp_asfd, buf, size, (off_t)addr) != size)
263 		return (PS_ERR);
264 
265 	return (PS_OK);
266 }
267 
268 ps_err_e
269 ps_pwrite(struct ps_prochandle *ph, psaddr_t addr, const void *buf, size_t size)
270 {
271 	if (pwrite(ph->pp_asfd, buf, size, (off_t)addr) != size)
272 		return (PS_ERR);
273 
274 	return (PS_OK);
275 }
276 
277 ps_err_e
278 ps_pglobal_sym(struct ps_prochandle *ph, const char *object_name,
279     const char *sym_name, ps_sym_t *symp)
280 {
281 	map_info_t	*mip;
282 	GElf_Sym	gsym;
283 
284 	if ((mip = str_to_map(ph, object_name)) == NULL)
285 		return (PS_ERR);
286 
287 	if (str_map_sym(sym_name, mip, &gsym, NULL) == RET_FAILED)
288 		return (PS_ERR);
289 
290 #if	defined(_LP64)
291 	*symp = gsym;
292 #else
293 	gelf_sym_to_elf32(&gsym, (Elf32_Sym *)symp);
294 #endif
295 
296 	return (PS_OK);
297 }
298 
299 ps_err_e
300 ps_pglobal_lookup(struct ps_prochandle *ph, const char *object_name,
301     const char *sym_name, ulong_t *sym_addr)
302 {
303 	GElf_Sym	sym;
304 	map_info_t	*mip;
305 
306 	if ((mip = str_to_map(ph, object_name)) == NULL)
307 		return (PS_ERR);
308 
309 	if (str_map_sym(sym_name, mip, &sym, NULL) == RET_FAILED)
310 		return (PS_ERR);
311 
312 	*sym_addr = sym.st_value;
313 
314 	return (PS_OK);
315 }
316 
317 ps_err_e
318 ps_lgetregs(struct ps_prochandle *ph, lwpid_t lid, prgregset_t gregset)
319 {
320 	char		procname[MAXPATHLEN];
321 	int		lwpfd;
322 	lwpstatus_t	lwpstatus;
323 
324 	(void) snprintf(procname, MAXPATHLEN - 1,
325 	    "/proc/%d/lwp/%d/lwpstatus", EC_SWORD(ph->pp_pid), EC_SWORD(lid));
326 
327 	if ((lwpfd = open(procname, O_RDONLY)) == -1)
328 		return (PS_ERR);
329 
330 	if (read(lwpfd, &lwpstatus, sizeof (lwpstatus)) == -1)
331 		return (PS_ERR);
332 
333 	(void) memcpy(gregset, lwpstatus.pr_reg, sizeof (*gregset));
334 
335 	(void) close(lwpfd);
336 	return (PS_OK);
337 }
338 
339 void
340 ps_plog(const char *fmt, ...)
341 {
342 	va_list		args;
343 	static FILE	*log_fp = NULL;
344 
345 	if (log_fp == NULL) {
346 		char		log_fname[256];
347 		(void) sprintf(log_fname, "/tmp/tdlog.%d", EC_SWORD(getpid()));
348 		if ((log_fp = fopen(log_fname, "w")) == NULL) {
349 			/*
350 			 * Unable to open log file - default to stderr.
351 			 */
352 			(void) fprintf(stderr, "unable to open %s, logging "
353 			    "redirected to stderr", log_fname);
354 			log_fp = stderr;
355 		}
356 	}
357 
358 	va_start(args, fmt);
359 	(void) vfprintf(log_fp, fmt, args);
360 	va_end(args);
361 	(void) fputc('\n', log_fp);
362 	(void) fflush(log_fp);
363 }
364 
365 /* ARGSUSED0 */
366 ps_err_e
367 ps_pbrandname(struct ps_prochandle *P, char *buf, size_t len)
368 {
369 	return (PS_ERR);
370 }
371