17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5ae115bc7Smrj * Common Development and Distribution License (the "License"). 6ae115bc7Smrj * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22ae115bc7Smrj * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* 297c478bd9Sstevel@tonic-gate * The KDI is used to allow the kernel debugger to directly invoke various 307c478bd9Sstevel@tonic-gate * kernel functions. In some cases, such as with kdi_mod_iter(), the 317c478bd9Sstevel@tonic-gate * debugger needs to execute functions that use the kernel's linker bindings. 327c478bd9Sstevel@tonic-gate * In other cases, the implementation of the KDI functions vary by platform 337c478bd9Sstevel@tonic-gate * and/or by CPU. By embedding the implementation of these functions in 347c478bd9Sstevel@tonic-gate * the platmod/cpumod, we can avoid the need for platform-specific knowledge 357c478bd9Sstevel@tonic-gate * in the debugger, and can thus have a single debugger binary for all 367c478bd9Sstevel@tonic-gate * platforms. 377c478bd9Sstevel@tonic-gate * 387c478bd9Sstevel@tonic-gate * There are three classes of KDI function: 397c478bd9Sstevel@tonic-gate * 407c478bd9Sstevel@tonic-gate * 1. Normal - These are functions whose implementations are in the kernel for 417c478bd9Sstevel@tonic-gate * convenience. An example is the modctl iterator, kdi_mod_iter. Using the 427c478bd9Sstevel@tonic-gate * modules symbol, this function iterates through the kernel's modctl list, 437c478bd9Sstevel@tonic-gate * invoking a debugger-provided callback for each one. This function is in 447c478bd9Sstevel@tonic-gate * the KDI because the debugger needs to be able to execute it in order to 457c478bd9Sstevel@tonic-gate * enable symbol resolution. Without symbol resolution, the debugger can't 467c478bd9Sstevel@tonic-gate * locate the modules symbol. A chicken-and-egg problem results. We solve 477c478bd9Sstevel@tonic-gate * this problem by locating the module iterator in the kernel, where run-time 487c478bd9Sstevel@tonic-gate * linking solves the problem for us. 497c478bd9Sstevel@tonic-gate * 507c478bd9Sstevel@tonic-gate * 2. CPU-specific - Functions in this class have implementations that differ 517c478bd9Sstevel@tonic-gate * by CPU. For example, the crosscall delivery notification method differs 527c478bd9Sstevel@tonic-gate * between Cheetah and Jalapeno, necessitating a different implementation for 537c478bd9Sstevel@tonic-gate * each. By locating the KDI implementation of these functions in the 547c478bd9Sstevel@tonic-gate * cpumods, we automatically get the correct implementation, as krtld 557c478bd9Sstevel@tonic-gate * automatically loads the correct cpumod when it starts. The cpumods 567c478bd9Sstevel@tonic-gate * directly fill in their portion of the kdi_t, using the mandatory 577c478bd9Sstevel@tonic-gate * cpu_kdi_init cpumod entry point. 587c478bd9Sstevel@tonic-gate * 597c478bd9Sstevel@tonic-gate * 3. Platform-specific - Similar to the CPU-specific class, platform-specific 607c478bd9Sstevel@tonic-gate * KDI functions have implementations that differ from platform to platform. 617c478bd9Sstevel@tonic-gate * As such, the implementations live in the platmods. Further 627c478bd9Sstevel@tonic-gate * differentiating the platform-specific KDI functions from their 637c478bd9Sstevel@tonic-gate * CPU-dependent brethren, many directly invoke PROM functions. This poses 647c478bd9Sstevel@tonic-gate * a problem, as the platmods use the kernel's promif functions, rather than 657c478bd9Sstevel@tonic-gate * the lock-free kmdb versions. We provide an interposition layer for these 667c478bd9Sstevel@tonic-gate * platform-specific calls that disables the pre- and post-processing 677c478bd9Sstevel@tonic-gate * functions used by the kernel to implement kernel-specific functionality 687c478bd9Sstevel@tonic-gate * that must not be executed when kmdb has control of the machine. Platmods 697c478bd9Sstevel@tonic-gate * fill in a kdi_plat_t using their optional plat_kdi_init entry point. 707c478bd9Sstevel@tonic-gate * krtld provides wrapper functions which suspend the necessary functions in 717c478bd9Sstevel@tonic-gate * the promif layer before invoking the kdi_plat_t functions (if any). 727c478bd9Sstevel@tonic-gate */ 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate #include <sys/types.h> 757c478bd9Sstevel@tonic-gate #include <sys/systm.h> 767c478bd9Sstevel@tonic-gate #include <sys/reboot.h> 777c478bd9Sstevel@tonic-gate #include <sys/kdi_impl.h> 787c478bd9Sstevel@tonic-gate 79*986fd29aSsetje #include <krtld/kobj_kdi.h> 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate #define KOBJ_KDI_MOD_IDLE 0 827c478bd9Sstevel@tonic-gate #define KOBJ_KDI_MOD_CHANGING 1 837c478bd9Sstevel@tonic-gate #define KOBJ_KDI_MOD_CHANGED 2 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate static int kobj_kdi_mod_state = KOBJ_KDI_MOD_IDLE; 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate extern int standalone; 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate cons_polledio_t * 907c478bd9Sstevel@tonic-gate kobj_kdi_get_polled_io(void) 917c478bd9Sstevel@tonic-gate { 927c478bd9Sstevel@tonic-gate cons_polledio_t **polled_io = &cons_polledio; 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate return (polled_io == NULL ? NULL : *polled_io); 957c478bd9Sstevel@tonic-gate } 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate int 987c478bd9Sstevel@tonic-gate kobj_kdi_mod_iter(int (*func)(struct modctl *, void *), void *arg) 997c478bd9Sstevel@tonic-gate { 1007c478bd9Sstevel@tonic-gate int rc; 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate if (standalone) { 1037c478bd9Sstevel@tonic-gate struct modctl_list *lp, **lpp; 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate for (lpp = kobj_linkmaps; *lpp != NULL; lpp++) { 1067c478bd9Sstevel@tonic-gate for (lp = *lpp; lp != NULL; lp = lp->modl_next) { 1077c478bd9Sstevel@tonic-gate if ((rc = func(lp->modl_modp, arg)) != 0) 1087c478bd9Sstevel@tonic-gate return (rc); 1097c478bd9Sstevel@tonic-gate } 1107c478bd9Sstevel@tonic-gate } 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate } else { 1137c478bd9Sstevel@tonic-gate struct modctl *modp = &modules; 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate do { 1167c478bd9Sstevel@tonic-gate if ((rc = func(modp, arg)) != 0) 1177c478bd9Sstevel@tonic-gate return (rc); 1187c478bd9Sstevel@tonic-gate } while ((modp = modp->mod_next) != &modules); 1197c478bd9Sstevel@tonic-gate } 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate return (0); 1227c478bd9Sstevel@tonic-gate } 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate int 1257c478bd9Sstevel@tonic-gate kobj_kdi_mod_isloaded(struct modctl *modp) 1267c478bd9Sstevel@tonic-gate { 1277c478bd9Sstevel@tonic-gate return (modp->mod_mp != NULL); 1287c478bd9Sstevel@tonic-gate } 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate int 1317c478bd9Sstevel@tonic-gate kobj_kdi_mods_changed(void) 1327c478bd9Sstevel@tonic-gate { 1337c478bd9Sstevel@tonic-gate int state; 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate if ((state = kobj_kdi_mod_state) == KOBJ_KDI_MOD_CHANGED) 1367c478bd9Sstevel@tonic-gate kobj_kdi_mod_state = KOBJ_KDI_MOD_IDLE; 1377c478bd9Sstevel@tonic-gate 1387c478bd9Sstevel@tonic-gate return (state != KOBJ_KDI_MOD_IDLE); 1397c478bd9Sstevel@tonic-gate } 1407c478bd9Sstevel@tonic-gate 1417c478bd9Sstevel@tonic-gate /*ARGSUSED1*/ 1427c478bd9Sstevel@tonic-gate void 1437c478bd9Sstevel@tonic-gate kobj_kdi_mod_notify(uint_t why, struct modctl *what) 1447c478bd9Sstevel@tonic-gate { 1457c478bd9Sstevel@tonic-gate switch (why) { 1467c478bd9Sstevel@tonic-gate case KOBJ_NOTIFY_MODLOADING: 1477c478bd9Sstevel@tonic-gate kobj_kdi_mod_state = KOBJ_KDI_MOD_CHANGING; 1487c478bd9Sstevel@tonic-gate break; 1497c478bd9Sstevel@tonic-gate case KOBJ_NOTIFY_MODLOADED: 1507c478bd9Sstevel@tonic-gate kobj_kdi_mod_state = KOBJ_KDI_MOD_CHANGED; 1517c478bd9Sstevel@tonic-gate if (boothowto & RB_DEBUG) 1527c478bd9Sstevel@tonic-gate kdi_dvec_mod_loaded(what); 1537c478bd9Sstevel@tonic-gate break; 1547c478bd9Sstevel@tonic-gate case KOBJ_NOTIFY_MODUNLOADING: 1557c478bd9Sstevel@tonic-gate kobj_kdi_mod_state = KOBJ_KDI_MOD_CHANGING; 1567c478bd9Sstevel@tonic-gate if (boothowto & RB_DEBUG) 1577c478bd9Sstevel@tonic-gate kdi_dvec_mod_unloading(what); 1587c478bd9Sstevel@tonic-gate break; 1597c478bd9Sstevel@tonic-gate case KOBJ_NOTIFY_MODUNLOADED: 1607c478bd9Sstevel@tonic-gate kobj_kdi_mod_state = KOBJ_KDI_MOD_CHANGED; 1617c478bd9Sstevel@tonic-gate break; 1627c478bd9Sstevel@tonic-gate } 1637c478bd9Sstevel@tonic-gate } 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate /* 1667c478bd9Sstevel@tonic-gate * Compare two modctl and module snapshots, attempting to determine whether 1677c478bd9Sstevel@tonic-gate * the module to which they both refer has changed between the time of the first 1687c478bd9Sstevel@tonic-gate * and the time of the second. We can't do a straight bcmp, because there are 1697c478bd9Sstevel@tonic-gate * fields that change in the normal course of operations. False positives 1707c478bd9Sstevel@tonic-gate * aren't the end of the world, but it'd be nice to avoid flagging a module 1717c478bd9Sstevel@tonic-gate * as changed every time someone holds or releases it. 1727c478bd9Sstevel@tonic-gate */ 1737c478bd9Sstevel@tonic-gate int 1747c478bd9Sstevel@tonic-gate kobj_kdi_mod_haschanged(struct modctl *mc1, struct module *mp1, 1757c478bd9Sstevel@tonic-gate struct modctl *mc2, struct module *mp2) 1767c478bd9Sstevel@tonic-gate { 1777c478bd9Sstevel@tonic-gate if (mc1->mod_loadcnt != mc2->mod_loadcnt || mc1->mod_mp != mc2->mod_mp) 1787c478bd9Sstevel@tonic-gate return (1); 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate if (mc1->mod_mp == NULL) 1817c478bd9Sstevel@tonic-gate return (0); 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate /* Take breath here. */ 1847c478bd9Sstevel@tonic-gate return (bcmp(&mp1->hdr, &mp2->hdr, sizeof (mp1->hdr)) != 0 || 1857c478bd9Sstevel@tonic-gate mp1->symhdr != mp2->symhdr || mp1->strhdr != mp2->strhdr || 1867c478bd9Sstevel@tonic-gate mp1->text != mp2->text || mp1->bss != mp2->bss || 1877c478bd9Sstevel@tonic-gate mp1->ctfdata != mp2->ctfdata || mp1->ctfsize != mp2->ctfsize); 1887c478bd9Sstevel@tonic-gate } 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate void 1917c478bd9Sstevel@tonic-gate kobj_kdi_system_claim(void) 1927c478bd9Sstevel@tonic-gate { 1937c478bd9Sstevel@tonic-gate kobj_kdi.kdi_plat_call(kobj_kdi.pkdi_system_claim); 1947c478bd9Sstevel@tonic-gate kobj_kdi.kdi_plat_call(kobj_kdi.pkdi_console_claim); 1957c478bd9Sstevel@tonic-gate } 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate void 1987c478bd9Sstevel@tonic-gate kobj_kdi_system_release(void) 1997c478bd9Sstevel@tonic-gate { 2007c478bd9Sstevel@tonic-gate kobj_kdi.kdi_plat_call(kobj_kdi.pkdi_console_release); 2017c478bd9Sstevel@tonic-gate kobj_kdi.kdi_plat_call(kobj_kdi.pkdi_system_release); 2027c478bd9Sstevel@tonic-gate } 2037c478bd9Sstevel@tonic-gate 2047c478bd9Sstevel@tonic-gate void 2057c478bd9Sstevel@tonic-gate kobj_kdi_init(void) 2067c478bd9Sstevel@tonic-gate { 2077c478bd9Sstevel@tonic-gate static const char *const initializers[] = { 2087c478bd9Sstevel@tonic-gate "cpu_kdi_init", "mach_kdi_init", "plat_kdi_init", NULL 2097c478bd9Sstevel@tonic-gate }; 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate Sym *sym; 2127c478bd9Sstevel@tonic-gate int i; 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate for (i = 0; initializers[i] != NULL; i++) { 2157c478bd9Sstevel@tonic-gate if ((sym = kobj_lookup_kernel(initializers[i])) != NULL) 2167c478bd9Sstevel@tonic-gate ((void (*)(kdi_t *))sym->st_value)(&kobj_kdi); 2177c478bd9Sstevel@tonic-gate } 2187c478bd9Sstevel@tonic-gate } 2197c478bd9Sstevel@tonic-gate 2207c478bd9Sstevel@tonic-gate kdi_t kobj_kdi = { 2217c478bd9Sstevel@tonic-gate KDI_VERSION, 2227c478bd9Sstevel@tonic-gate kobj_kdi_mods_changed, 2237c478bd9Sstevel@tonic-gate kobj_kdi_mod_iter, 2247c478bd9Sstevel@tonic-gate kobj_kdi_mod_isloaded, 2257c478bd9Sstevel@tonic-gate kobj_kdi_mod_haschanged, 2267c478bd9Sstevel@tonic-gate kobj_kdi_system_claim, 2277c478bd9Sstevel@tonic-gate kobj_kdi_system_release, 2287c478bd9Sstevel@tonic-gate kdi_pread, 2297c478bd9Sstevel@tonic-gate kdi_pwrite, 2307c478bd9Sstevel@tonic-gate kdi_flush_caches, 2317c478bd9Sstevel@tonic-gate kdi_range_is_nontoxic, 2327c478bd9Sstevel@tonic-gate kobj_kdi_get_polled_io, 2337c478bd9Sstevel@tonic-gate kdi_vtop, 2347c478bd9Sstevel@tonic-gate kdi_dtrace_get_state, 2357c478bd9Sstevel@tonic-gate kdi_dtrace_set, 2367c478bd9Sstevel@tonic-gate /* 2377c478bd9Sstevel@tonic-gate * The rest are filled in by cpu_kdi_init, mach_kdi_init, and/or 2387c478bd9Sstevel@tonic-gate * plat_kdi_init. 2397c478bd9Sstevel@tonic-gate */ 2407c478bd9Sstevel@tonic-gate NULL, /* kdi_plat_call */ 241ae115bc7Smrj NULL, /* kdi_kmdb_enter */ 2427c478bd9Sstevel@tonic-gate { NULL }, /* kdi_arch */ 2437c478bd9Sstevel@tonic-gate { NULL } /* kdi_plat */ 2447c478bd9Sstevel@tonic-gate }; 245