prb_rtld.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* 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 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Interfaces to sync up with run time linker (rtld) at process start up time
* and at dlopen() and dlclose() time
* In Solaris 2.6, librtld_db.so should replace this functionality. Issues
* to solve before libtnfctl.so can use librtld_db.so:
* 1. Should libtnfctl.so be usable before Solaris 2.6 - If so, cannot use
* librtld_db.so
* 2. libtnfctl.so will have to provide <proc_service.h> in order to use
* librtld_db.so. If libtnfctl.so is now linked into a debugger that
* also provides <proc_service.h>, how will the two co-exist - will the
* linker get confused, or not ?
*/
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <link.h>
#include "tnfctl.h"
#include "prb_proc_int.h"
#include "dbg.h"
/* ---------------------------------------------------------------- */
/* ----------------------- Public Functions ----------------------- */
/* ---------------------------------------------------------------- */
/*
* prb_rtld_stalk() - setup for a breakpoint when rtld has opened or closed a
* shared object.
*/
{
"prb_rtld_stalk: dbgaddr not set\n"));
return (PRB_STATUS_BADARG);
}
"prb_rtld_stalk: error in d_un.d_ptr\n"));
return (prbstat);
}
/* read in the debug struct that it points to */
if (prbstat)
return (prbstat);
}
/* plant a breakpoint trap in the pointed to function */
if (prbstat)
return (prbstat);
/* setup process to stop when breakpoint encountered */
return (prbstat);
}
/*
* prb_rtld_unstalk() - remove rtld breakpoint
*/
{
/* turn off BPT tracing while out of the water ... */
return (prbstat);
}
/*
* prb_rtld_advance() - we've hit a breakpoint, replace the original
* instruction, istep, put the breakpoint back ...
*/
{
if (prbstat)
return (prbstat);
if (prbstat)
return (prbstat);
if (prbstat)
return (prbstat);
if (prbstat)
return (prbstat);
return (PRB_STATUS_OK);
}
/*
* checks if process has reached rtld_sync point or not i.e. has rltld
* loaded in libraries or not ? If not, it lets process run until
* rtld has mapped in all libraries (no user code would have been
* executed, including .init sections)
*/
{
if (prbstat)
return (prbstat);
/* wait on target to sync up after rtld maps in all .so's */
if (prbstat)
return (prbstat);
}
return (prbstat);
}
/* ---------------------------------------------------------------- */
/* ----------------------- Private Functions ---------------------- */
/* ---------------------------------------------------------------- */
/*
* prb_rtld_setup() - turns on the flag in the rtld structure so that rtld
* executes a getpid() stystem call after it done mapping all shared objects
* but before it executes any init code.
*/
static prb_status_t
{
"prb_rtld_setup: dbgaddr not set\n"));
return (PRB_STATUS_BADARG);
}
sizeof (dentry));
if (prbstat) {
"prb_rtld_setup: error in d_un.d_ptr\n"));
return (prbstat);
}
} else {
return (PRB_STATUS_OK);
}
/* modify it - i.e. request rtld to do getpid() */
sizeof (dentry));
return (prbstat);
}
/*
* prb_rtld_wait() - waits on target to execute getpid()
*/
static prb_status_t
{
/* stop on exit of getpid() */
if (prbstat) {
"prb_rtld_wait: couldn't set up child to stop on "
return (prbstat);
}
/* stop on entry of exit() - i.e. exec failed */
if (prbstat) {
"prb_rtld_wait: couldn't set up child to stop on "
return (prbstat);
}
/* continue target and wait for it to stop */
if (prbstat) {
"prb_rtld_wait: couldn't continue target process: %s\n",
return (prbstat);
}
/* wait for target to stop */
if (prbstat) {
"prb_rtld_wait: couldn't wait on target process: %s\n",
return (prbstat);
}
/* make sure it did stop on getpid() */
if (prbstat) {
"prb_rtld_wait: couldn't get state of target: %s\n",
return (prbstat);
}
return (prb_status_map(EACCES));
}
/* catch any other errors */
"prb_rtld_wait: target didn't stop on getpid\n"));
return (PRB_STATUS_BADSYNC);
}
/* clear wait on getpid */
if (prbstat) {
"prb_rtld_wait: couldn't clear child to stop on "
return (prbstat);
}
/* clear wait on exit */
if (prbstat) {
"prb_rtld_wait: couldn't clear child to stop on "
return (prbstat);
}
/* start-stop the process to clear it out of the system call */
if (prbstat) {
"prb_rtld_wait: couldn't prstop child: %s\n",
return (prbstat);
}
return (PRB_STATUS_OK);
}
#if defined(__sparc)
#define INS_BPT 0x91d02001
#define INS_BPT 0xcc
#else
#endif
/*
* plants a breakpoint at the specified location in
* the target process, and saves the existing instruction.
*/
static prb_status_t
{
if (!proc_p->bpt_inserted) {
if (prbstat)
return (prbstat);
if (prbstat)
return (prbstat);
}
return (PRB_STATUS_OK);
}
/*
* removes a breakpoint at the specified location in
* the target process, and replaces it with the original instruction.
*/
{
if (proc_p->bpt_inserted) {
if (prbstat)
return (prbstat);
}
return (PRB_STATUS_OK);
}