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