xref: /illumos-gate/usr/src/cmd/sgs/librtld_db/common/rtld_db.c (revision 4de2612967d06c4fdbf524a62556a1e8118a006f)
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 2004 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 
30 #include	<stdlib.h>
31 #include	<stdio.h>
32 #include	<proc_service.h>
33 #include	<link.h>
34 #include	<rtld_db.h>
35 #include	<rtld.h>
36 #include	<_rtld_db.h>
37 #include	<msg.h>
38 
39 
40 /*
41  * Mutex to protect global data
42  */
43 mutex_t	glob_mutex = DEFAULTMUTEX;
44 int	rtld_db_version = RD_VERSION1;
45 int	rtld_db_logging = 0;
46 
47 
48 void
49 rd_log(const int on_off)
50 {
51 	(void) mutex_lock(&glob_mutex);
52 	rtld_db_logging = on_off;
53 	(void) mutex_unlock(&glob_mutex);
54 	LOG(ps_plog(MSG_ORIG(MSG_DB_LOGENABLE)));
55 }
56 
57 /*
58  * Versioning Notes.
59  *
60  * The following have been added as the versions of librtld_db
61  * have grown:
62  *
63  *	RD_VERSION1:
64  *		o baseline version
65  *
66  *	RD_VERSION2:
67  *		o added support for the use of the AT_SUN_LDBASE auxvector
68  *		  to find the initialial debugging (r_debug) structures
69  *		  in ld.so.1
70  *		o added the rl_dynamic field to rd_loadobj_t
71  *		o added the RD_FLG_MEM_OBJECT to be used with the
72  *		  rl_dynamic->rl_flags field.
73  *
74  *	RD_VERSION3:
75  *		o added the following fields/flags to the rd_plt_info_t
76  *		  type:
77  *			pi_baddr	- bound address of PLT (if bound)
78  *			pi_flags	- flag field
79  *			RD_FLG_PI_PLTBOUND	(flag for pi_flags)
80  *				if set - the PLT is bound and pi_baddr
81  *				is filled in with the destination of the PLT.
82  *
83  *	RD_VERSION4:
84  *		o added the following field to the rd_loadobj_t structure:
85  *			rl_tlsmodid	- module ID for TLS references
86  */
87 rd_err_e
88 rd_init(int version)
89 {
90 	if ((version < RD_VERSION1) ||
91 	    (version > RD_VERSION))
92 		return (RD_NOCAPAB);
93 	rtld_db_version = version;
94 	LOG(ps_plog(MSG_ORIG(MSG_DB_RDINIT), rtld_db_version));
95 	return (RD_OK);
96 }
97 
98 
99 rd_err_e
100 rd_reset(struct rd_agent *rap)
101 {
102 	rd_err_e			err;
103 
104 	RDAGLOCK(rap);
105 
106 	rap->rd_flags = 0;
107 
108 #ifdef _LP64
109 	/*
110 	 * Determine if client is 32-bit or 64-bit.
111 	 */
112 	if (ps_pdmodel(rap->rd_psp, &rap->rd_dmodel) != PS_OK) {
113 		LOG(ps_plog(MSG_ORIG(MSG_DB_DMLOOKFAIL)));
114 		RDAGUNLOCK(rap);
115 		return (RD_DBERR);
116 	}
117 
118 	if (rap->rd_dmodel == PR_MODEL_LP64)
119 		err = _rd_reset64(rap);
120 	else
121 #endif
122 		err = _rd_reset32(rap);
123 
124 	RDAGUNLOCK(rap);
125 	return (err);
126 }
127 
128 
129 rd_agent_t *
130 rd_new(struct ps_prochandle *php)
131 {
132 	rd_agent_t	*rap;
133 
134 	LOG(ps_plog(MSG_ORIG(MSG_DB_RDNEW), php));
135 	if ((rap = (rd_agent_t *)calloc(sizeof (rd_agent_t), 1)) == NULL)
136 		return (0);
137 
138 	rap->rd_psp = php;
139 	(void) mutex_init(&rap->rd_mutex, USYNC_THREAD, 0);
140 	if (rd_reset(rap) != RD_OK) {
141 		free(rap);
142 		LOG(ps_plog(MSG_ORIG(MSG_DB_RESETFAIL)));
143 		return ((rd_agent_t *)0);
144 	}
145 
146 	return (rap);
147 }
148 
149 
150 void
151 rd_delete(rd_agent_t *rap)
152 {
153 	LOG(ps_plog(MSG_ORIG(MSG_DB_RDDELETE), rap));
154 	free(rap);
155 }
156 
157 
158 rd_err_e
159 rd_loadobj_iter(rd_agent_t *rap, rl_iter_f *cb, void *client_data)
160 {
161 	rd_err_e	err;
162 
163 	RDAGLOCK(rap);
164 
165 #ifdef _LP64
166 	if (rap->rd_dmodel == PR_MODEL_LP64)
167 		err = _rd_loadobj_iter64(rap, cb, client_data);
168 	else
169 #endif
170 		err = _rd_loadobj_iter32(rap, cb, client_data);
171 
172 	RDAGUNLOCK(rap);
173 	return (err);
174 }
175 
176 
177 rd_err_e
178 rd_plt_resolution(rd_agent_t *rap, psaddr_t pc, lwpid_t lwpid,
179 	psaddr_t pltbase, rd_plt_info_t *rpi)
180 {
181 	rd_err_e	err;
182 	RDAGLOCK(rap);
183 #ifdef	_LP64
184 	if (rap->rd_dmodel == PR_MODEL_LP64)
185 		err = plt64_resolution(rap, pc, lwpid, pltbase,
186 		    rpi);
187 	else
188 #endif
189 		err = plt32_resolution(rap, pc, lwpid, pltbase,
190 		    rpi);
191 	RDAGUNLOCK(rap);
192 	return (err);
193 }
194 
195 rd_err_e
196 rd_event_addr(rd_agent_t *rap, rd_event_e num, rd_notify_t *np)
197 {
198 	rd_err_e	rc = RD_OK;
199 
200 	RDAGLOCK(rap);
201 	switch (num) {
202 	case RD_NONE:
203 		break;
204 	case RD_PREINIT:
205 		np->type = RD_NOTIFY_BPT;
206 		np->u.bptaddr = rap->rd_preinit;
207 		break;
208 	case RD_POSTINIT:
209 		np->type = RD_NOTIFY_BPT;
210 		np->u.bptaddr = rap->rd_postinit;
211 		break;
212 	case RD_DLACTIVITY:
213 		np->type = RD_NOTIFY_BPT;
214 		np->u.bptaddr = rap->rd_dlact;
215 		break;
216 	default:
217 		LOG(ps_plog(MSG_ORIG(MSG_DB_UNEXPEVENT), num));
218 		rc = RD_ERR;
219 		break;
220 	}
221 	if (rc == RD_OK) {
222 		LOG(ps_plog(MSG_ORIG(MSG_DB_RDEVENTADDR), num,
223 			EC_ADDR(np->u.bptaddr)));
224 	}
225 
226 	RDAGUNLOCK(rap);
227 	return (rc);
228 }
229 
230 
231 /* ARGSUSED 0 */
232 rd_err_e
233 rd_event_enable(rd_agent_t *rap, int onoff)
234 {
235 	rd_err_e	err;
236 
237 	RDAGLOCK(rap);
238 
239 #ifdef _LP64
240 	if (rap->rd_dmodel == PR_MODEL_LP64)
241 		err = _rd_event_enable64(rap, onoff);
242 	else
243 #endif
244 		err = _rd_event_enable32(rap, onoff);
245 
246 	RDAGUNLOCK(rap);
247 	return (err);
248 }
249 
250 
251 rd_err_e
252 rd_event_getmsg(rd_agent_t *rap, rd_event_msg_t *emsg)
253 {
254 	rd_err_e	err;
255 
256 	RDAGLOCK(rap);
257 
258 #ifdef _LP64
259 	if (rap->rd_dmodel == PR_MODEL_LP64)
260 		err = _rd_event_getmsg64(rap, emsg);
261 	else
262 #endif
263 		err = _rd_event_getmsg32(rap, emsg);
264 
265 	RDAGUNLOCK(rap);
266 	return (err);
267 }
268 
269 
270 rd_err_e
271 rd_binder_exit_addr(struct rd_agent *rap, const char *bname, psaddr_t *beaddr)
272 {
273 	ps_sym_t	sym;
274 
275 	if (rap->rd_tbinder) {
276 		*beaddr = rap->rd_tbinder;
277 		return (RD_OK);
278 	}
279 	if (ps_pglobal_sym(rap->rd_psp, PS_OBJ_LDSO, bname, &sym) != PS_OK) {
280 		LOG(ps_plog(MSG_ORIG(MSG_DB_UNFNDSYM),
281 		    bname));
282 		return (RD_ERR);
283 	}
284 
285 	rap->rd_tbinder = *beaddr = sym.st_value + sym.st_size - M_BIND_ADJ;
286 
287 	return (RD_OK);
288 }
289 
290 
291 rd_err_e
292 rd_objpad_enable(struct rd_agent *rap, size_t padsize)
293 {
294 	rd_err_e	err;
295 
296 	RDAGLOCK(rap);
297 
298 #ifdef _LP64
299 	if (rap->rd_dmodel == PR_MODEL_LP64)
300 		err = _rd_objpad_enable64(rap, padsize);
301 	else
302 #endif
303 		err = _rd_objpad_enable32(rap, padsize);
304 
305 	RDAGUNLOCK(rap);
306 	return (err);
307 }
308 
309 
310 char *
311 rd_errstr(rd_err_e rderr)
312 {
313 	/*
314 	 * Convert an 'rd_err_e' to a string
315 	 */
316 	switch (rderr) {
317 	case RD_OK:
318 		return ((char *)MSG_ORIG(MSG_ER_OK));
319 	case RD_ERR:
320 		return ((char *)MSG_ORIG(MSG_ER_ERR));
321 	case RD_DBERR:
322 		return ((char *)MSG_ORIG(MSG_ER_DBERR));
323 	case RD_NOCAPAB:
324 		return ((char *)MSG_ORIG(MSG_ER_NOCAPAB));
325 	case RD_NODYNAM:
326 		return ((char *)MSG_ORIG(MSG_ER_NODYNAM));
327 	case RD_NOBASE:
328 		return ((char *)MSG_ORIG(MSG_ER_NOBASE));
329 	case RD_NOMAPS:
330 		return ((char *)MSG_ORIG(MSG_ER_NOMAPS));
331 	default:
332 		return ((char *)MSG_ORIG(MSG_ER_DEFAULT));
333 	}
334 }
335