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 #include <sys/types.h> 29 #include <sys/cmn_err.h> 30 #include <sys/modctl.h> 31 #include <sys/kobj.h> 32 #include <sys/kobj_impl.h> 33 #include <sys/promif.h> 34 #include <sys/promimpl.h> 35 #include <sys/reboot.h> 36 #include <sys/bootconf.h> 37 #include <sys/systm.h> /* strstr */ 38 #include <sys/machsystm.h> /* obpdebug */ 39 40 #define FDEBUGFILE "misc/forthdebug" 41 #define INSTALL_DBP "kdbg-words dbp-install previous" 42 #define SYMBOL_END "END OF SYMBOL" 43 44 #ifdef DEBUG 45 static int forthdebug = 1; 46 #else 47 static int forthdebug = 0; 48 #endif /* DEBUG */ 49 50 static int forthdebug_dbp = 0; 51 int forthdebug_supported = 1; 52 int modreloc_flag = KOBJ_RELOCATED; 53 54 /* 55 * basic_sym[] holds all essential symbols the symbol lookup 56 * service requires. Forthdebug stub names appears in forthdebug 57 * as place holders. They are replaced with the value of corresponding 58 * kernel variables. For example, "modules-val-here" in forthdebug 59 * is replaced with the address of "modules" variable. 60 * 61 * To improve performance, we mandate the records be in the same 62 * sequence they appear in forthdebug, i.e "modules-val-here" is 63 * ahead of "primaries-v-here" in misc/forthdebug. 64 * 65 * The last record must be all 0 to indicate end of the array. 66 */ 67 static char *basic_sym[] = { 68 /* kernel variable */ /* forthdebug stub name - must be 16 chars */ 69 "modules", "modules-val-here", 70 "primaries", "primaries-v-here", 71 "modreloc_flag", "modreloc-flagval", 72 0, 0 73 }; 74 75 static void fdbp_hook() {} /* null function for defer breakpoint operation */ 76 77 /*ARGSUSED*/ 78 static void fdbp_snoop(unsigned int i, struct modctl *modctl_p) 79 { 80 promif_preprom(); 81 fdbp_hook(); 82 promif_postprom(); 83 } 84 85 static kobj_notify_list_t knl_load = { 86 fdbp_snoop, KOBJ_NOTIFY_MODLOADED, 0, 0 87 }; 88 89 static kobj_notify_list_t knl_unload = { 90 fdbp_snoop, KOBJ_NOTIFY_MODUNLOADING, 0, 0 91 }; 92 93 void 94 forthdebug_init(void) 95 { 96 char *fth_buf, *buf_p; 97 ulong_t modsym; 98 int i, sz; 99 struct bootstat bstat; 100 struct _buf *file; 101 102 if (!forthdebug_supported) { 103 (void) modload("misc", "obpsym"); 104 return; 105 } 106 107 forthdebug_dbp |= boothowto & RB_FORTHDEBUGDBP; 108 forthdebug |= (boothowto & RB_FORTHDEBUG) | forthdebug_dbp; 109 110 file = kobj_open_path(FDEBUGFILE, 1, 1); 111 if (file == (struct _buf *)-1) { 112 cmn_err(CE_CONT, "Can't open %s\n", FDEBUGFILE); 113 return; 114 } 115 116 i = BOP_FSTAT(bootops, file->_fd, &bstat); 117 if (i || !bstat.st_size) { 118 cmn_err(CE_CONT, "Can't stat %s stat=%x sz=%llx\n", 119 FDEBUGFILE, i, (long long)bstat.st_size); 120 goto err_stat; 121 } 122 123 fth_buf = (char *)kobj_zalloc(bstat.st_size + 1, KM_SLEEP); 124 sz = kobj_read_file(file, fth_buf, bstat.st_size, 0); /* entire file */ 125 if (sz < 0) { 126 cmn_err(CE_CONT, "Error(%d) reading %s\n", sz, FDEBUGFILE); 127 goto done; 128 } 129 ASSERT(bstat.st_size == sz); 130 fth_buf[sz] = 0; 131 132 /* resolve all essential symbols in basic_sym[] */ 133 for (i = 0; basic_sym[i]; i += 2) { 134 buf_p = strstr(fth_buf, basic_sym[i + 1]); 135 modsym = kobj_getsymvalue(basic_sym[i], 0); 136 if (buf_p && modsym) { 137 (void) sprintf(buf_p, "%16p", (void *)modsym); 138 buf_p += 16; 139 *buf_p++ = ' '; /* erase null char by sprintf */ 140 } else { 141 cmn_err(CE_CONT, 142 "forthdebug_init: No %s symbol(%p,%p), aborted\n", 143 basic_sym[i], (void *)buf_p, (void *)modsym); 144 goto done; 145 } 146 } 147 if (!forthdebug) { /* symbol lookup services only */ 148 if (!(buf_p = strstr(fth_buf, SYMBOL_END))) { 149 cmn_err(CE_CONT, "No %s in forthdebug\n", SYMBOL_END); 150 goto done; 151 } 152 *buf_p = '\0'; 153 #ifdef DEBUG 154 cmn_err(CE_CONT, "symbol lookup service (%ld bytes)\n", 155 (long)(buf_p - fth_buf)); 156 #endif /* DEBUG */ 157 prom_interpret(fth_buf, 0, 0, 0, 0, 0); 158 goto done; 159 } 160 161 cmn_err(CE_CONT, "%s (%d bytes) ", FDEBUGFILE, sz); 162 prom_interpret(fth_buf, 0, 0, 0, 0, 0); 163 cmn_err(CE_CONT, "loaded\n"); 164 obpdebug = 1; /* backward compatibility */ 165 166 if (forthdebug_dbp) { 167 #ifdef NO_KOBJ_NOTIFY 168 modsym = kobj_getsymvalue("kobj_notify_add", 0); 169 (void) ((int (*)(kobj_notify_list_t *))modsym)(&knl_load); 170 (void) ((int (*)(kobj_notify_list_t *))modsym)(&knl_unload); 171 #else 172 (void) kobj_notify_add(&knl_load); 173 (void) kobj_notify_add(&knl_unload); 174 #endif /* NO_KOBJ_NOTIFY */ 175 prom_interpret(INSTALL_DBP, 0, 0, 0, 0, 0); 176 debug_enter("Defer breakpoint enabled. Add breakpoints, then"); 177 } 178 done: 179 kobj_free(fth_buf, bstat.st_size + 1); 180 err_stat: 181 kobj_close_file(file); 182 183 if (boothowto & RB_HALT) 184 debug_enter("forthdebug: halt flag (-h) is set.\n"); 185 } 186