Home | History | Annotate | Download | only in kmdb
      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 2007 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  * The KDI, or kernel/debugger interface, is used to allow the kernel and the
     30  * debugger to communicate.  These communications take two forms:
     31  *
     32  *  1. kernel to debugger.  Interfaces of this type are used by the kernel to
     33  *     inform the debugger of changes in the state of the system that need to
     34  *     be noted by the debugger.  For example, the kernel uses one of these
     35  *     interfaces to tell debugger that the set of currently-loaded modules
     36  *     has changed.
     37  *
     38  *  2. debugger to kernel.  Interfaces of this type are used by the debugger
     39  *     to extract information from the kernel that would otherwise be difficult
     40  *     to get, or to perform services that are specific to the machine being
     41  *     used.  An example of the former is the module iterator, which is needed
     42  *     to allow symbol resolution, but which needs to resolve symbols prior
     43  *     to the iteration.  The latter class include machine-specific or
     44  *     cpu-type-specific functions, such as the I-cache flusher.  By directly
     45  *     using the kernel versions of these functions, we avoid the need to
     46  *     include multiple versions of each function - one per cpu and/or machine -
     47  *     in kmdb.
     48  */
     49 
     50 #include <sys/kdi_impl.h>
     51 
     52 #include <kmdb/kmdb_kdi.h>
     53 #include <kmdb/kmdb_dpi.h>
     54 #include <kmdb/kmdb_kvm.h>
     55 #include <kmdb/kmdb_promif.h>
     56 #include <mdb/mdb_debug.h>
     57 #include <mdb/mdb_err.h>
     58 #include <mdb/mdb.h>
     59 
     60 static int kdi_unload_request;
     61 
     62 typedef struct mod_interp_data {
     63 	int	(*mid_usercb)(struct modctl *, void *);
     64 	void	*mid_userarg;
     65 	jmp_buf mid_pcb;
     66 	jmp_buf *mid_oldpcb;
     67 } mod_interp_data_t;
     68 
     69 static kmdb_auxv_t *kdi_auxv;
     70 
     71 int
     72 kmdb_kdi_mods_changed(void)
     73 {
     74 	return (mdb.m_kdi->kdi_mods_changed());
     75 }
     76 
     77 static int
     78 kmdb_kdi_mod_interp(struct modctl *mp, void *arg)
     79 {
     80 	mod_interp_data_t *mid = arg;
     81 	int rc;
     82 
     83 	kmdb_dpi_restore_fault_hdlr(mid->mid_oldpcb);
     84 	rc = mid->mid_usercb(mp, mid->mid_userarg);
     85 	mid->mid_oldpcb = kmdb_dpi_set_fault_hdlr(&mid->mid_pcb);
     86 
     87 	return (rc);
     88 }
     89 
     90 /*
     91  * We need to protect ourselves against any problems that may occur while
     92  * executing the module iterator, currently located in krtld.  If, for
     93  * example, one of the next pointers in the module list points to an invalid
     94  * address, we don't want kmdb to explode.  As such, we protect ourselves
     95  * with the DPI fault-protection routines.  We don't want our fault-protection
     96  * callback to protect the callback that the kmdb consumer provided, so we
     97  * provide our own interposition callback that removes our fault-protector
     98  * before invoking the user's callback.
     99  */
    100 int
    101 kmdb_kdi_mod_iter(int (*cb)(struct modctl *, void *), void *arg)
    102 {
    103 	mod_interp_data_t mid;
    104 	int rc;
    105 
    106 	if (setjmp(mid.mid_pcb) != 0) {
    107 		/* We took a fault while iterating through the modules */
    108 		kmdb_dpi_restore_fault_hdlr(mid.mid_oldpcb);
    109 		return (-1);
    110 	}
    111 
    112 	mid.mid_usercb = cb;
    113 	mid.mid_userarg = arg;
    114 	mid.mid_oldpcb = kmdb_dpi_set_fault_hdlr(&mid.mid_pcb);
    115 
    116 	rc = mdb.m_kdi->kdi_mod_iter(kmdb_kdi_mod_interp, &mid);
    117 
    118 	kmdb_dpi_restore_fault_hdlr(mid.mid_oldpcb);
    119 
    120 	return (rc);
    121 }
    122 
    123 int
    124 kmdb_kdi_mod_isloaded(struct modctl *modp)
    125 {
    126 	return (mdb.m_kdi->kdi_mod_isloaded(modp));
    127 }
    128 
    129 int
    130 kmdb_kdi_mod_haschanged(struct modctl *mc1, struct module *mp1,
    131     struct modctl *mc2, struct module *mp2)
    132 {
    133 	return (mdb.m_kdi->kdi_mod_haschanged(mc1, mp1, mc2, mp2));
    134 }
    135 
    136 static ssize_t
    137 kdi_prw(void *buf, size_t nbytes, physaddr_t addr, int (*rw)(caddr_t, size_t,
    138     physaddr_t, size_t *))
    139 {
    140 	size_t sz;
    141 	int rc;
    142 
    143 	kmdb_dpi_flush_slave_caches();
    144 	if ((rc = rw(buf, nbytes, addr, &sz)) != 0)
    145 		return (set_errno(rc));
    146 
    147 	return (sz);
    148 }
    149 
    150 ssize_t
    151 kmdb_kdi_pread(void *buf, size_t nbytes, physaddr_t addr)
    152 {
    153 	return (kdi_prw(buf, nbytes, addr, mdb.m_kdi->kdi_pread));
    154 }
    155 
    156 ssize_t
    157 kmdb_kdi_pwrite(void *buf, size_t nbytes, physaddr_t addr)
    158 {
    159 	return (kdi_prw(buf, nbytes, addr, mdb.m_kdi->kdi_pwrite));
    160 }
    161 
    162 void
    163 kmdb_kdi_flush_caches(void)
    164 {
    165 	mdb.m_kdi->kdi_flush_caches();
    166 }
    167 
    168 int
    169 kmdb_kdi_get_unload_request(void)
    170 {
    171 	return (kdi_unload_request);
    172 }
    173 
    174 void
    175 kmdb_kdi_set_unload_request(void)
    176 {
    177 	kdi_unload_request = 1;
    178 }
    179 
    180 int
    181 kmdb_kdi_get_flags(void)
    182 {
    183 	uint_t flags = 0;
    184 
    185 	if (mdb.m_flags & MDB_FL_NOCTF)
    186 		flags |= KMDB_KDI_FL_NOCTF;
    187 	if (mdb.m_flags & MDB_FL_NOMODS)
    188 		flags |= KMDB_KDI_FL_NOMODS;
    189 
    190 	return (flags);
    191 }
    192 
    193 size_t
    194 kmdb_kdi_range_is_nontoxic(uintptr_t va, size_t sz, int write)
    195 {
    196 	return (mdb.m_kdi->kdi_range_is_nontoxic(va, sz, write));
    197 }
    198 
    199 void
    200 kmdb_kdi_system_claim(void)
    201 {
    202 	(void) kmdb_dpi_call((uintptr_t)mdb.m_kdi->kdi_system_claim, 0, NULL);
    203 	kmdb_prom_debugger_entry();
    204 }
    205 
    206 void
    207 kmdb_kdi_system_release(void)
    208 {
    209 	kmdb_prom_debugger_exit();
    210 
    211 	if (mdb.m_kdi->kdi_system_release != NULL) {
    212 		(void) kmdb_dpi_call((uintptr_t)mdb.m_kdi->kdi_system_release,
    213 		    0, NULL);
    214 	}
    215 }
    216 
    217 struct cons_polledio *
    218 kmdb_kdi_get_polled_io(void)
    219 {
    220 	return (mdb.m_kdi->kdi_get_polled_io());
    221 }
    222 
    223 void
    224 kmdb_kdi_kmdb_enter(void)
    225 {
    226 	mdb.m_kdi->kdi_kmdb_enter();
    227 }
    228 
    229 int
    230 kmdb_kdi_vtop(uintptr_t va, physaddr_t *pap)
    231 {
    232 	jmp_buf pcb, *oldpcb;
    233 	int rc = 0;
    234 
    235 	if (setjmp(pcb) == 0) {
    236 		int err;
    237 
    238 		oldpcb = kmdb_dpi_set_fault_hdlr(&pcb);
    239 
    240 		if ((err = mdb.m_kdi->kdi_vtop(va, pap)) != 0)
    241 			rc = set_errno(err == ENOENT ? EMDB_NOMAP : err);
    242 	} else {
    243 		/* We faulted during the translation */
    244 		rc = set_errno(EMDB_NOMAP);
    245 	}
    246 
    247 	kmdb_dpi_restore_fault_hdlr(oldpcb);
    248 
    249 	return (rc);
    250 }
    251 
    252 kdi_dtrace_state_t
    253 kmdb_kdi_dtrace_get_state(void)
    254 {
    255 	return (mdb.m_kdi->kdi_dtrace_get_state());
    256 }
    257 
    258 int
    259 kmdb_kdi_dtrace_set(int state)
    260 {
    261 	int err;
    262 
    263 	if ((err = mdb.m_kdi->kdi_dtrace_set(state)) != 0)
    264 		return (set_errno(err));
    265 
    266 	return (0);
    267 }
    268 
    269 /*
    270  * This function is to be called only during kmdb initialization, as it
    271  * uses the running kernel for symbol translation facilities.
    272  */
    273 uintptr_t
    274 kmdb_kdi_lookup_by_name(char *modname, char *symname)
    275 {
    276 	ASSERT(kmdb_dpi_get_state(NULL) == DPI_STATE_INIT);
    277 
    278 	return (kdi_auxv->kav_lookup_by_name(modname, symname));
    279 }
    280 
    281 void
    282 kmdb_kdi_init(kdi_t *kdi, kmdb_auxv_t *kav)
    283 {
    284 	mdb.m_kdi = kdi;
    285 	mdb.m_pagesize = kav->kav_pagesize;
    286 
    287 	kdi_unload_request = 0;
    288 
    289 	kdi_auxv = kav;
    290 
    291 	kmdb_kdi_init_isadep(kdi, kav);
    292 }
    293 
    294 void
    295 kmdb_kdi_end_init(void)
    296 {
    297 	kdi_auxv = NULL;
    298 }
    299