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