/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (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 * or http://www.opensolaris.org/os/licensing. * 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 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * The KDI, or kernel/debugger interface, is used to allow the kernel and the * debugger to communicate. These communications take two forms: * * 1. kernel to debugger. Interfaces of this type are used by the kernel to * inform the debugger of changes in the state of the system that need to * be noted by the debugger. For example, the kernel uses one of these * interfaces to tell debugger that the set of currently-loaded modules * has changed. * * 2. debugger to kernel. Interfaces of this type are used by the debugger * to extract information from the kernel that would otherwise be difficult * to get, or to perform services that are specific to the machine being * used. An example of the former is the module iterator, which is needed * to allow symbol resolution, but which needs to resolve symbols prior * to the iteration. The latter class include machine-specific or * cpu-type-specific functions, such as the I-cache flusher. By directly * using the kernel versions of these functions, we avoid the need to * include multiple versions of each function - one per cpu and/or machine - * in kmdb. */ #include #include #include #include #include #include #include #include static int kdi_unload_request; typedef struct mod_interp_data { int (*mid_usercb)(struct modctl *, void *); void *mid_userarg; jmp_buf mid_pcb; jmp_buf *mid_oldpcb; } mod_interp_data_t; static kmdb_auxv_t *kdi_auxv; int kmdb_kdi_mods_changed(void) { return (mdb.m_kdi->kdi_mods_changed()); } static int kmdb_kdi_mod_interp(struct modctl *mp, void *arg) { mod_interp_data_t *mid = arg; int rc; kmdb_dpi_restore_fault_hdlr(mid->mid_oldpcb); rc = mid->mid_usercb(mp, mid->mid_userarg); mid->mid_oldpcb = kmdb_dpi_set_fault_hdlr(&mid->mid_pcb); return (rc); } /* * We need to protect ourselves against any problems that may occur while * executing the module iterator, currently located in krtld. If, for * example, one of the next pointers in the module list points to an invalid * address, we don't want kmdb to explode. As such, we protect ourselves * with the DPI fault-protection routines. We don't want our fault-protection * callback to protect the callback that the kmdb consumer provided, so we * provide our own interposition callback that removes our fault-protector * before invoking the user's callback. */ int kmdb_kdi_mod_iter(int (*cb)(struct modctl *, void *), void *arg) { mod_interp_data_t mid; int rc; if (setjmp(mid.mid_pcb) != 0) { /* We took a fault while iterating through the modules */ kmdb_dpi_restore_fault_hdlr(mid.mid_oldpcb); return (-1); } mid.mid_usercb = cb; mid.mid_userarg = arg; mid.mid_oldpcb = kmdb_dpi_set_fault_hdlr(&mid.mid_pcb); rc = mdb.m_kdi->kdi_mod_iter(kmdb_kdi_mod_interp, &mid); kmdb_dpi_restore_fault_hdlr(mid.mid_oldpcb); return (rc); } int kmdb_kdi_mod_isloaded(struct modctl *modp) { return (mdb.m_kdi->kdi_mod_isloaded(modp)); } int kmdb_kdi_mod_haschanged(struct modctl *mc1, struct module *mp1, struct modctl *mc2, struct module *mp2) { return (mdb.m_kdi->kdi_mod_haschanged(mc1, mp1, mc2, mp2)); } static ssize_t kdi_prw(void *buf, size_t nbytes, physaddr_t addr, int (*rw)(caddr_t, size_t, physaddr_t, size_t *)) { size_t sz; int rc; kmdb_dpi_flush_slave_caches(); if ((rc = rw(buf, nbytes, addr, &sz)) != 0) return (set_errno(rc)); return (sz); } ssize_t kmdb_kdi_pread(void *buf, size_t nbytes, physaddr_t addr) { return (kdi_prw(buf, nbytes, addr, mdb.m_kdi->kdi_pread)); } ssize_t kmdb_kdi_pwrite(void *buf, size_t nbytes, physaddr_t addr) { return (kdi_prw(buf, nbytes, addr, mdb.m_kdi->kdi_pwrite)); } void kmdb_kdi_flush_caches(void) { mdb.m_kdi->kdi_flush_caches(); } int kmdb_kdi_get_unload_request(void) { return (kdi_unload_request); } void kmdb_kdi_set_unload_request(void) { kdi_unload_request = 1; } int kmdb_kdi_get_flags(void) { uint_t flags = 0; if (mdb.m_flags & MDB_FL_NOCTF) flags |= KMDB_KDI_FL_NOCTF; if (mdb.m_flags & MDB_FL_NOMODS) flags |= KMDB_KDI_FL_NOMODS; return (flags); } size_t kmdb_kdi_range_is_nontoxic(uintptr_t va, size_t sz, int write) { return (mdb.m_kdi->kdi_range_is_nontoxic(va, sz, write)); } void kmdb_kdi_system_claim(void) { (void) kmdb_dpi_call((uintptr_t)mdb.m_kdi->kdi_system_claim, 0, NULL); kmdb_prom_debugger_entry(); } void kmdb_kdi_system_release(void) { kmdb_prom_debugger_exit(); if (mdb.m_kdi->kdi_system_release != NULL) { (void) kmdb_dpi_call((uintptr_t)mdb.m_kdi->kdi_system_release, 0, NULL); } } struct cons_polledio * kmdb_kdi_get_polled_io(void) { return (mdb.m_kdi->kdi_get_polled_io()); } void kmdb_kdi_kmdb_enter(void) { mdb.m_kdi->kdi_kmdb_enter(); } int kmdb_kdi_vtop(uintptr_t va, physaddr_t *pap) { jmp_buf pcb, *oldpcb; int rc = 0; if (setjmp(pcb) == 0) { int err; oldpcb = kmdb_dpi_set_fault_hdlr(&pcb); if ((err = mdb.m_kdi->kdi_vtop(va, pap)) != 0) rc = set_errno(err == ENOENT ? EMDB_NOMAP : err); } else { /* We faulted during the translation */ rc = set_errno(EMDB_NOMAP); } kmdb_dpi_restore_fault_hdlr(oldpcb); return (rc); } kdi_dtrace_state_t kmdb_kdi_dtrace_get_state(void) { return (mdb.m_kdi->kdi_dtrace_get_state()); } int kmdb_kdi_dtrace_set(int state) { int err; if ((err = mdb.m_kdi->kdi_dtrace_set(state)) != 0) return (set_errno(err)); return (0); } /* * This function is to be called only during kmdb initialization, as it * uses the running kernel for symbol translation facilities. */ uintptr_t kmdb_kdi_lookup_by_name(char *modname, char *symname) { ASSERT(kmdb_dpi_get_state(NULL) == DPI_STATE_INIT); return (kdi_auxv->kav_lookup_by_name(modname, symname)); } void kmdb_kdi_init(kdi_t *kdi, kmdb_auxv_t *kav) { mdb.m_kdi = kdi; mdb.m_pagesize = kav->kav_pagesize; kdi_unload_request = 0; kdi_auxv = kav; kmdb_kdi_init_isadep(kdi, kav); } void kmdb_kdi_end_init(void) { kdi_auxv = NULL; }