brand_librtld_db.c revision 12199:2dbcb597eb37
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) 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26#include <assert.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <strings.h>
31#include <libproc.h>
32#include <proc_service.h>
33#include <synch.h>
34#include <sys/types.h>
35#include <sys/link.h>
36#include <rtld_db.h>
37#include <sys/brand.h>
38
39/*
40 * ATTENTION:
41 *	Librtl_db brand plugin libraries should NOT directly invoke any
42 *	libproc.so interfaces or be linked against libproc.  If a librtl_db
43 *	brand plugin library uses libproc.so interfaces then it may break
44 *	any other librtld_db consumers (like mdb) that tries to attach
45 *	to a branded process.  The only safe interfaces that the a librtld_db
46 *	brand plugin library can use to access a target process are the
47 *	proc_service(3PROC) apis.
48 */
49
50/*
51 * M_DATA comes from some streams header file but is also redifined in
52 * _rtld_db.h, so nuke the old streams definition here.
53 */
54#ifdef M_DATA
55#undef M_DATA
56#endif /* M_DATA */
57
58/*
59 * For 32-bit versions of this library, this file get's compiled once.
60 * For 64-bit versions of this library, this file get's compiled twice,
61 * once with _ELF64 defined and once without.  The expectation is that
62 * the 64-bit version of the library can properly deal with both 32-bit
63 * and 64-bit elf files, hence in the 64-bit library there are two copies
64 * of all the interfaces in this file, one set named *32 and one named *64.
65 *
66 * This also means that we need to be careful when declaring local pointers
67 * that point to objects in another processes address space, since these
68 * pointers may not match the current processes pointer width.  Basically,
69 * we should not use any objects that change size between 32 and 64 bit
70 * modes like: long, void *, uintprt_t, caddr_t, psaddr_t, size_t, etc.
71 * Instead we should declare all pointers as uint32_t.  Then when we
72 * are compiled to deal with 64-bit targets we'll re-define uing32_t
73 * to be a uint64_t.
74 */
75#ifdef _LP64
76#ifdef _ELF64
77#define	uint32_t			uint64_t
78#define	Elf32_Dyn			Elf64_Dyn
79#define	validate_rdebug32		validate_rdebug64
80#define	_rd_loadobj_iter32		_rd_loadobj_iter64
81#define	_rd_get_dyns32			_rd_get_dyns64
82#define	dummy_ldb32			dummy_ldb64
83#define	dummy_ldb_init32		dummy_ldb_init64
84#define	dummy_ldb_fini32		dummy_ldb_fini64
85#define	dummy_ldb_loadobj_iter32	dummy_ldb_loadobj_iter64
86#define	dummy_ldb_get_dyns32		dummy_ldb_get_dyns64
87#define	brand_ldb_init32		brand_ldb_init64
88#define	brand_ldb_fini32		brand_ldb_fini64
89#define	brand_ldb_loadobj_iter32	brand_ldb_loadobj_iter64
90#define	brand_ldb_get_dyns32		brand_ldb_get_dyns64
91#endif /* _ELF64 */
92#endif /* _LP64 */
93
94/* Included from usr/src/cmd/sgs/librtld_db/common */
95#include <_rtld_db.h>
96
97/*ARGSUSED*/
98static rd_helper_data_t
99dummy_ldb_init32(rd_agent_t *rap, struct ps_prochandle *php)
100{
101	return (NULL);
102}
103
104/*ARGSUSED*/
105static void
106dummy_ldb_fini32(rd_helper_data_t rhd)
107{
108}
109
110/*ARGSUSED*/
111static int
112dummy_ldb_loadobj_iter32(rd_helper_data_t rhd, rl_iter_f *cb, void *client_data)
113{
114	return (RD_OK);
115}
116
117/*ARGSUSED*/
118static rd_err_e
119dummy_ldb_get_dyns32(rd_helper_data_t rhd,
120    psaddr_t addr, void **dynpp, size_t *dynpp_sz)
121{
122	*dynpp = NULL;
123	*dynpp_sz = 0;
124	return (RD_OK);
125}
126
127static rd_helper_ops_t dummy_ldb32 = {
128	LM_ID_BRAND,
129	dummy_ldb_init32,
130	dummy_ldb_fini32,
131	dummy_ldb_loadobj_iter32,
132	dummy_ldb_get_dyns32
133};
134
135static uint32_t
136brand_ldb_getauxval32(struct ps_prochandle *php, int type)
137{
138	const auxv_t		*auxvp = NULL;
139
140	if (ps_pauxv(php, &auxvp) != PS_OK)
141		return ((uint32_t)-1);
142
143	while (auxvp->a_type != AT_NULL) {
144		if (auxvp->a_type == type)
145			return ((uint32_t)(uintptr_t)auxvp->a_un.a_ptr);
146		auxvp++;
147	}
148	return ((uint32_t)-1);
149}
150
151/*
152 * Normally, the native Solaris librtldb_db plugin uses a bunch of different
153 * methods to try and find the rdebug structure associated with the target
154 * process we're debugging.  For details on the different methods see
155 * _rd_reset32().  Thankfully our job is easier.  We know that the brand
156 * library is always linked against the native linker, and when the
157 * process was first executed we saved off a pointer to the brand linkers
158 * rdebug structure in one of our brand specific aux vectors,
159 * AT_SUN_BRAND_COMMON_LDDATA.  So we'll just look that up here.
160 */
161/*ARGSUSED*/
162static rd_helper_data_t
163brand_ldb_init32(rd_agent_t *rap, struct ps_prochandle *php)
164{
165	struct rd_agent	*rap_new;
166	uint32_t	lddata_addr;
167	int		rd_dmodel;
168
169	if (ps_pdmodel(php, &rd_dmodel) != PS_OK) {
170		ps_plog("brand_ldb_init: lookup of data model failed");
171		return (NULL);
172	}
173#ifdef _ELF64
174	assert(rd_dmodel == PR_MODEL_LP64);
175#else /* !_ELF64 */
176	assert(rd_dmodel == PR_MODEL_ILP32);
177#endif /* !_ELF64 */
178
179	lddata_addr = brand_ldb_getauxval32(php, AT_SUN_BRAND_COMMON_LDDATA);
180	if (lddata_addr == (uint32_t)-1) {
181		ps_plog("brand_ldb_init: no LDDATA found in aux vector");
182		return (NULL);
183	}
184	ps_plog("brand_ldb_init: found LDDATA auxv ld.so.1 data seg "
185	    "at: 0x%p", lddata_addr);
186
187	/*
188	 * Ok.  So this is kinda ugly.  Basically we know that we're going to
189	 * be parsing data from link maps that are generated by a Solaris
190	 * linker.  As it turns out, that's exactly what the default
191	 * Solaris librtld_db library is designed to do.  So rather than
192	 * duplicate all that link map parsing code here we'll simply
193	 * invoke the native librtld_db that normally does this, and when
194	 * we do we'll point them at our emulation libraries link map.
195	 *
196	 * Of course these interfacess aren't really public interfaces
197	 * and they take a "struct rd_agent" as a parameter.  So here
198	 * we'll allocate and initialize a new "struct rd_agent", point
199	 * it at our emulation libraries link map, and initialize just
200	 * enough of the structure to make the librtld_db interfaces
201	 * that we want to use happy.
202	 */
203	if ((rap_new = calloc(sizeof (*rap_new), 1)) == NULL) {
204		ps_plog("brand_ldb_init: can't allocate memory");
205		return (NULL);
206	}
207	rap_new->rd_dmodel = rd_dmodel;
208	rap_new->rd_psp = php;
209	rap_new->rd_rdebug = lddata_addr;
210	(void) mutex_init(&rap_new->rd_mutex, USYNC_THREAD, 0);
211
212	/*
213	 * When we get invoked from librtld_db, and we call back into it,
214	 * librtld_db will once again check if there is a plugin and
215	 * invoke it.  Since we don't want to enter a recursive loop
216	 * we're going to specify a different plugin interface for
217	 * our linkmap, and these new plugin interfaces won't actually
218	 * do anything other than return.
219	 */
220	rap_new->rd_helper.rh_ops = &dummy_ldb32;
221
222	/*
223	 * validate_rdebug32() requires the following "struct rd_agent"
224	 * members to be initialized:
225	 *	rd_psp, rd_rdebug
226	 *
227	 * validate_rdebug32() initializes the following "struct rd_agent"
228	 * members:
229	 *	rd_flags, rd_rdebugvers, rd_rtlddbpriv
230	 */
231	if (validate_rdebug32(rap_new) != RD_OK) {
232		ps_plog("brand_ldb_init: can't find valid r_debug data");
233		free(rap_new);
234		return (NULL);
235	}
236
237	ps_plog("brand_ldb_init: finished, helper_data=0x%p", rap_new);
238	return ((rd_helper_data_t)rap_new);
239}
240
241static void
242brand_ldb_fini32(rd_helper_data_t rhd)
243{
244	struct rd_agent	*rap = (struct rd_agent *)rhd;
245	ps_plog("brand_ldb_fini: cleaning up brand helper");
246	free(rap);
247}
248
249/*ARGSUSED*/
250static int
251brand_ldb_loadobj_iter32(rd_helper_data_t rhd, rl_iter_f *cb, void *client_data)
252{
253	struct rd_agent	*rap = (struct rd_agent *)rhd;
254	int		err;
255
256	ps_plog("brand_ldb_loadobj_iter(helper_data=0x%p)", rhd);
257	assert(rap->rd_psp == php);
258	RDAGLOCK(rap);
259	/*
260	 * _rd_loadobj_iter32() requires the following "struct rd_agent"
261	 * members to be initialized:
262	 * 	rd_rtlddbpriv, rd_rdebugvers, rd_flags,
263	 * 	rd_helper.rh_ops, rd_dmodel
264	 */
265	err = _rd_loadobj_iter32(rap, cb, client_data);
266	RDAGUNLOCK(rap);
267	ps_plog("brand_ldb_loadobj_iter: finished, err = %d", err);
268	return (err);
269}
270
271/*ARGSUSED*/
272static rd_err_e
273brand_ldb_get_dyns32(rd_helper_data_t rhd,
274    psaddr_t addr, void **dynpp, size_t *dynpp_sz)
275{
276	struct rd_agent	*rap = (struct rd_agent *)rhd;
277	int		err;
278
279	ps_plog("brand_ldb_get_dyns(helper_data=0x%p)", rhd);
280	err = _rd_get_dyns32(rap, addr, (Elf32_Dyn **)dynpp, dynpp_sz);
281	ps_plog("brand_ldb_get_dyns: finished, err = %d", err);
282	return (err);
283}
284
285/*
286 * Librtld_db plugin linkage struct.
287 *
288 * When we get loaded by librtld_db, it will look for the symbol below
289 * to find our plugin entry points.
290 */
291rd_helper_ops_t RTLD_DB_BRAND_OPS = {
292	LM_ID_NONE,
293	brand_ldb_init32,
294	brand_ldb_fini32,
295	brand_ldb_loadobj_iter32,
296	brand_ldb_get_dyns32
297};
298