Home | History | Annotate | Line # | Download | only in dist
      1 /*
      2  * Copyright (c) 2010 The FreeBSD Foundation
      3  * All rights reserved.
      4  *
      5  * This software was developed by Rui Paulo under sponsorship from the
      6  * FreeBSD Foundation.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     27  * SUCH DAMAGE.
     28  */
     29 #include <sys/cdefs.h>
     30 #ifdef __FBSDID
     31 __FBSDID("$FreeBSD: head/lib/librtld_db/rtld_db.c 272488 2014-10-03 23:20:37Z markj $");
     32 #else
     33 __RCSID("$NetBSD: rtld_db.c,v 1.3 2016/04/26 14:26:49 chs Exp $");
     34 #endif
     35 
     36 #include <sys/types.h>
     37 #include <sys/sysctl.h>
     38 
     39 #include <inttypes.h>
     40 #include <err.h>
     41 #include <stdio.h>
     42 #include <stdlib.h>
     43 #include <string.h>
     44 #include <limits.h>
     45 #include <libproc.h>
     46 #include <util.h>
     47 
     48 #include "rtld_db.h"
     49 
     50 static int _librtld_db_debug = 0;
     51 #define DPRINTF(...) do {				\
     52 	if (_librtld_db_debug) {			\
     53 		fprintf(stderr, "librtld_db: DEBUG: ");	\
     54 		fprintf(stderr, __VA_ARGS__);		\
     55 	}						\
     56 } while (0)
     57 
     58 void
     59 rd_delete(rd_agent_t *rdap)
     60 {
     61 
     62 	free(rdap);
     63 }
     64 
     65 const char *
     66 rd_errstr(rd_err_e rderr)
     67 {
     68 
     69 	switch (rderr) {
     70 	case RD_ERR:
     71 		return "generic error";
     72 	case RD_OK:
     73 		return "no error";
     74 	case RD_NOCAPAB:
     75 		return "capability not supported";
     76 	case RD_DBERR:
     77 		return "database error";
     78 	case RD_NOBASE:
     79 		return "NOBASE";
     80 	case RD_NOMAPS:
     81 		return "NOMAPS";
     82 	default:
     83 		return "unknown error";
     84 	}
     85 }
     86 
     87 rd_err_e
     88 rd_event_addr(rd_agent_t *rdap, rd_event_e event, rd_notify_t *notify)
     89 {
     90 	rd_err_e ret;
     91 
     92 	DPRINTF("%s rdap %p event %d notify %p\n", __func__, rdap, event,
     93 	    notify);
     94 
     95 	ret = RD_OK;
     96 	switch (event) {
     97 	case RD_NONE:
     98 		break;
     99 	case RD_PREINIT:
    100 		notify->type = RD_NOTIFY_BPT;
    101 		notify->u.bptaddr = rdap->rda_preinit_addr;
    102 		break;
    103 	case RD_POSTINIT:
    104 		notify->type = RD_NOTIFY_BPT;
    105 		notify->u.bptaddr = rdap->rda_postinit_addr;
    106 		break;
    107 	case RD_DLACTIVITY:
    108 		notify->type = RD_NOTIFY_BPT;
    109 		notify->u.bptaddr = rdap->rda_dlactivity_addr;
    110 		break;
    111 	default:
    112 		ret = RD_ERR;
    113 		break;
    114 	}
    115 	return (ret);
    116 }
    117 
    118 rd_err_e
    119 rd_event_enable(rd_agent_t *rdap __unused, int onoff)
    120 {
    121 	DPRINTF("%s onoff %d\n", __func__, onoff);
    122 
    123 	return (RD_OK);
    124 }
    125 
    126 rd_err_e
    127 rd_event_getmsg(rd_agent_t *rdap __unused, rd_event_msg_t *msg)
    128 {
    129 	DPRINTF("%s\n", __func__);
    130 
    131 	msg->type = RD_POSTINIT;
    132 	msg->u.state = RD_CONSISTENT;
    133 
    134 	return (RD_OK);
    135 }
    136 
    137 rd_err_e
    138 rd_init(int version)
    139 {
    140 	char *debug = NULL;
    141 
    142 	if (version == RD_VERSION) {
    143 		debug = getenv("LIBRTLD_DB_DEBUG");
    144 		_librtld_db_debug = debug ? atoi(debug) : 0;
    145 		return (RD_OK);
    146 	} else
    147 		return (RD_NOCAPAB);
    148 }
    149 
    150 rd_err_e
    151 rd_loadobj_iter(rd_agent_t *rdap, rl_iter_f *cb, void *clnt_data)
    152 {
    153 	size_t cnt, i, lastvn = 0;
    154 	rd_loadobj_t rdl;
    155 	struct kinfo_vmentry *kves, *kve;
    156 
    157 	DPRINTF("%s\n", __func__);
    158 
    159         if ((kves = kinfo_getvmmap(proc_getpid(rdap->rda_php), &cnt)) == NULL) {
    160 		warn("ERROR: kinfo_getvmmap() failed");
    161 		return (RD_ERR);
    162 	}
    163 	for (i = 0; i < cnt; i++) {
    164 		kve = kves + i;
    165 		if (kve->kve_type == KVME_TYPE_VNODE)
    166 			lastvn = i;
    167 		memset(&rdl, 0, sizeof(rdl));
    168 		/*
    169 		 * Map the kinfo_vmentry struct to the rd_loadobj structure.
    170 		 */
    171 		rdl.rdl_saddr = kve->kve_start;
    172 		rdl.rdl_eaddr = kve->kve_end;
    173 		rdl.rdl_offset = kve->kve_offset;
    174 		if (kve->kve_protection & KVME_PROT_READ)
    175 			rdl.rdl_prot |= RD_RDL_R;
    176 		if (kve->kve_protection & KVME_PROT_WRITE)
    177 			rdl.rdl_prot |= RD_RDL_W;
    178 		if (kve->kve_protection & KVME_PROT_EXEC)
    179 			rdl.rdl_prot |= RD_RDL_X;
    180 		strlcpy(rdl.rdl_path, kves[lastvn].kve_path,
    181 			sizeof(rdl.rdl_path));
    182 		(*cb)(&rdl, clnt_data);
    183 	}
    184 	free(kves);
    185 
    186 	return (RD_OK);
    187 }
    188 
    189 void
    190 rd_log(const int onoff)
    191 {
    192 	DPRINTF("%s\n", __func__);
    193 
    194 	(void)onoff;
    195 }
    196 
    197 rd_agent_t *
    198 rd_new(struct proc_handle *php)
    199 {
    200 	rd_agent_t *rdap;
    201 
    202 	rdap = malloc(sizeof(rd_agent_t));
    203 	if (rdap) {
    204 		memset(rdap, 0, sizeof(rd_agent_t));
    205 		rdap->rda_php = php;
    206 		rd_reset(rdap);
    207 	}
    208 
    209 	return (rdap);
    210 }
    211 
    212 rd_err_e
    213 rd_objpad_enable(rd_agent_t *rdap, size_t padsize)
    214 {
    215 	DPRINTF("%s\n", __func__);
    216 
    217 	(void)rdap;
    218 	(void)padsize;
    219 
    220 	return (RD_ERR);
    221 }
    222 
    223 rd_err_e
    224 rd_plt_resolution(rd_agent_t *rdap, uintptr_t pc, struct proc *proc,
    225     uintptr_t plt_base, rd_plt_info_t *rpi)
    226 {
    227 	DPRINTF("%s\n", __func__);
    228 
    229 	(void)rdap;
    230 	(void)pc;
    231 	(void)proc;
    232 	(void)plt_base;
    233 	(void)rpi;
    234 
    235 	return (RD_ERR);
    236 }
    237 
    238 rd_err_e
    239 rd_reset(rd_agent_t *rdap)
    240 {
    241 	GElf_Sym sym;
    242 
    243 	/*
    244 	 * preinit and dlactivity events are not supported yet.
    245 	 */
    246 
    247 	rdap->rda_preinit_addr = (uintptr_t)-1;
    248 	rdap->rda_dlactivity_addr = (uintptr_t)-1;
    249 
    250 	if (proc_name2sym(rdap->rda_php, "ld.elf_so", "_rtld_debug_state",
    251 	    &sym, NULL) < 0)
    252 		return (RD_ERR);
    253 	DPRINTF("found _rtld_debug_state at 0x%lx\n",
    254 	    (unsigned long)sym.st_value);
    255 	rdap->rda_postinit_addr = sym.st_value;
    256 
    257 	return (RD_OK);
    258 }
    259