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 2008 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 <dlfcn.h>
30#include <sys/modctl.h>
31#include <sys/kobj.h>
32
33#include <kmdb/kmdb_module.h>
34#include <mdb/mdb_debug.h>
35#include <mdb/mdb_gelf.h>
36#include <mdb/mdb_string.h>
37#include <mdb/mdb.h>
38
39/*
40 * kmdb libdl-style interface for the manipulation of dmods.
41 */
42
43static char *dl_errstr;
44
45static kmdb_modctl_t *
46dl_name2ctl(const char *pathname)
47{
48	mdb_var_t *v;
49
50	if ((v = mdb_nv_lookup(&mdb.m_dmodctl, strbasename(pathname))) ==
51	    NULL)
52		return (NULL);
53
54	return ((kmdb_modctl_t *)MDB_NV_COOKIE(v));
55}
56
57/*ARGSUSED*/
58void *
59dlmopen(Lmid_t lmid, const char *pathname, int mode)
60{
61	kmdb_modctl_t *kmc;
62
63	if ((kmc = dl_name2ctl(pathname)) == NULL) {
64		dl_errstr = "unregistered module";
65		return (NULL);
66	}
67
68	kmc->kmc_dlrefcnt++;
69
70	dl_errstr = NULL;
71
72	return (kmc);
73}
74
75int
76dlclose(void *dlp)
77{
78	kmdb_modctl_t *kmc = dlp;
79
80	dl_errstr = NULL;
81
82	ASSERT(kmc->kmc_dlrefcnt > 0);
83	if (--kmc->kmc_dlrefcnt > 0)
84		return (0);
85
86	return (0);
87}
88
89char *
90dlerror(void)
91{
92	char *str = dl_errstr;
93
94	dl_errstr = NULL;
95
96	return (str);
97}
98
99static void *
100dl_findsym(kmdb_modctl_t *kmc, const char *name)
101{
102	GElf_Sym sym;
103	uint_t symid;
104
105	if (mdb_gelf_symtab_lookup_by_name(kmc->kmc_symtab, name, &sym,
106	    &symid) < 0)
107		return (NULL);
108
109	return ((void *)(uintptr_t)sym.st_value);
110}
111
112/*ARGSUSED*/
113void *
114dlsym(void *dlp, const char *name)
115{
116	kmdb_modctl_t *kmc = dlp;
117	mdb_var_t *v;
118	void *addr;
119
120	switch ((uintptr_t)dlp) {
121	case (uintptr_t)RTLD_NEXT:
122		mdb_nv_rewind(&mdb.m_dmodctl);
123		while ((v = mdb_nv_advance(&mdb.m_dmodctl)) != NULL) {
124			if ((addr = dl_findsym(MDB_NV_COOKIE(v), name)) != NULL)
125				break;
126		}
127		break;
128
129	case (uintptr_t)RTLD_DEFAULT:
130	case (uintptr_t)RTLD_SELF:
131		dl_errstr = "invalid handle";
132		return (NULL);
133
134	default:
135		addr = dl_findsym(kmc, name);
136	}
137
138	dl_errstr = (addr == NULL) ? "symbol not found" : NULL;
139
140	return (addr);
141}
142
143#pragma weak _dladdr1 = dladdr1
144/*ARGSUSED*/
145int
146dladdr1(void *address, Dl_info *dlip, void **info, int flags)
147{
148	/*
149	 * umem uses this for debugging information.  We'll pretend to fail.
150	 */
151
152	return (0);
153}
154