/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2000-2001 by Sun Microsystems, Inc.
* All rights reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* libthread_db (tdb) cache
*
* In order to properly debug multi-threaded programs, the proc target must be
* able to query and modify information such as a thread's register set using
* either the native LWP services provided by libproc (if the process is not
* linked with libthread), or using the services provided by libthread_db (if
* the process is linked with libthread). Additionally, a process may begin
* life as a single-threaded process and then later dlopen() libthread, so we
* must be prepared to switch modes on-the-fly. There are also two possible
* cannot link mdb against libthread_db directly; instead, we must dlopen the
* appropriate libthread_db on-the-fly based on which libthread.so the victim
* process has open. Finally, mdb is designed so that multiple targets can be
* active simultaneously, so we could even have *both* libthread_db's open at
* the same time. This might happen if you were looking at two multi-threaded
* user processes inside of a crash dump, one using /usr/lib/libthread.so and
* the other using /usr/lib/lwp/libthread.so. To meet these requirements, we
* implement a libthread_db "cache" in this file. The proc target calls
* mdb_tdb_load() with the pathname of a libthread_db to load, and if it is
* not already open, we dlopen() it, look up the symbols we need to reference,
* and fill in an ops vector which we return to the caller. Once an object is
* loaded, we don't bother unloading it unless the entire cache is explicitly
* flushed. This mechanism also has the nice property that we don't bother
* loading libthread_db until we need it, so the debugger starts up faster.
*/
#include <mdb/mdb_modapi.h>
#include <strings.h>
#include <unistd.h>
#include <dlfcn.h>
#include <link.h>
static td_err_e
{
return (TD_NOCAPAB); /* return thread_db code for not supported */
}
const mdb_tdb_ops_t *
{
mdb_tdb_lib_t *t;
void *hdl;
/*
* Search through the existing cache of thread_db libraries and see if
* we have this one loaded already. If so, just return its ops vector.
*/
break;
}
if (t != NULL)
return (&t->tdb_ops);
/*
* Otherwise dlmopen the new library, look up its td_init() function,
* and call it. If any of this fails, we return NULL for failure.
*/
return (NULL);
return (NULL);
}
return (NULL);
}
return (NULL);
}
/*
* If td_init() succeeds, we can't fail from here on. Allocate a new
* library entry and add it to our linked list.
*/
t->tdb_handle = hdl;
tdb_list = t;
/*
* For each function we need to call in the thread_db library, look it
* up using dlsym(). If we find it, add it to the ops vector. If not,
* put the address of our default function (see above) in that slot.
*/
#ifdef __sparc
#endif /* __sparc */
return (&t->tdb_ops);
}
void
mdb_tdb_flush(void)
{
mdb_tdb_lib_t *t, *u;
u = t->tdb_next;
(void) dlclose(t->tdb_handle);
mdb_free(t, sizeof (mdb_tdb_lib_t));
}
}