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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <sys/cmn_err.h> 31 #include <sys/modctl.h> 32 #include <sys/kobj.h> 33 #include <sys/kobj_impl.h> 34 #include <sys/promif.h> 35 #include <sys/promimpl.h> 36 #include <sys/reboot.h> 37 #include <sys/bootconf.h> 38 #include <sys/systm.h> /* strstr */ 39 #include <sys/machsystm.h> /* obpdebug */ 40 41 #define FDEBUGFILE "misc/forthdebug" 42 #define INSTALL_DBP "kdbg-words dbp-install previous" 43 #define SYMBOL_END "END OF SYMBOL" 44 45 #ifdef DEBUG 46 static int forthdebug = 1; 47 #else 48 static int forthdebug = 0; 49 #endif /* DEBUG */ 50 51 static int forthdebug_dbp = 0; 52 int forthdebug_supported = 1; 53 int modreloc_flag = KOBJ_RELOCATED; 54 55 /* 56 * basic_sym[] holds all essential symbols the symbol lookup 57 * service requires. Forthdebug stub names appears in forthdebug 58 * as place holders. They are replaced with the value of corresponding 59 * kernel variables. For example, "modules-val-here" in forthdebug 60 * is replaced with the address of "modules" variable. 61 * 62 * To improve performance, we mandate the records be in the same 63 * sequence they appear in forthdebug, i.e "modules-val-here" is 64 * ahead of "primaries-v-here" in misc/forthdebug. 65 * 66 * The last record must be all 0 to indicate end of the array. 67 */ 68 static char *basic_sym[] = { 69 /* kernel variable */ /* forthdebug stub name - must be 16 chars */ 70 "modules", "modules-val-here", 71 "primaries", "primaries-v-here", 72 "modreloc_flag", "modreloc-flagval", 73 0, 0 74 }; 75 76 static void fdbp_hook() {} /* null function for defer breakpoint operation */ 77 78 /*ARGSUSED*/ 79 static void fdbp_snoop(unsigned int i, struct modctl *modctl_p) 80 { 81 promif_preprom(); 82 fdbp_hook(); 83 promif_postprom(); 84 } 85 86 static kobj_notify_list_t knl_load = { 87 fdbp_snoop, KOBJ_NOTIFY_MODLOADED, 0, 0 88 }; 89 90 static kobj_notify_list_t knl_unload = { 91 fdbp_snoop, KOBJ_NOTIFY_MODUNLOADING, 0, 0 92 }; 93 94 void 95 forthdebug_init(void) 96 { 97 char *fth_buf, *buf_p; 98 ulong_t modsym; 99 int i, sz; 100 struct bootstat bstat; 101 struct _buf *file; 102 103 if (!forthdebug_supported) { 104 (void) modload("misc", "obpsym"); 105 return; 106 } 107 108 forthdebug_dbp |= boothowto & RB_FORTHDEBUGDBP; 109 forthdebug |= (boothowto & RB_FORTHDEBUG) | forthdebug_dbp; 110 111 file = kobj_open_path(FDEBUGFILE, 1, 1); 112 if (file == (struct _buf *)-1) { 113 cmn_err(CE_CONT, "Can't open %s\n", FDEBUGFILE); 114 return; 115 } 116 117 i = BOP_FSTAT(bootops, file->_fd, &bstat); 118 if (i || !bstat.st_size) { 119 cmn_err(CE_CONT, "Can't stat %s stat=%x sz=%llx\n", 120 FDEBUGFILE, i, (long long)bstat.st_size); 121 goto err_stat; 122 } 123 124 fth_buf = (char *)kobj_zalloc(bstat.st_size + 1, KM_SLEEP); 125 sz = kobj_read_file(file, fth_buf, bstat.st_size, 0); /* entire file */ 126 if (sz < 0) { 127 cmn_err(CE_CONT, "Error(%d) reading %s\n", sz, FDEBUGFILE); 128 goto done; 129 } 130 ASSERT(bstat.st_size == sz); 131 fth_buf[sz] = 0; 132 133 /* resolve all essential symbols in basic_sym[] */ 134 for (i = 0; basic_sym[i]; i += 2) { 135 buf_p = strstr(fth_buf, basic_sym[i + 1]); 136 modsym = kobj_getsymvalue(basic_sym[i], 0); 137 if (buf_p && modsym) { 138 (void) sprintf(buf_p, "%16p", (void *)modsym); 139 buf_p += 16; 140 *buf_p++ = ' '; /* erase null char by sprintf */ 141 } else { 142 cmn_err(CE_CONT, 143 "forthdebug_init: No %s symbol(%p,%p), aborted\n", 144 basic_sym[i], (void *)buf_p, (void *)modsym); 145 goto done; 146 } 147 } 148 if (!forthdebug) { /* symbol lookup services only */ 149 if (!(buf_p = strstr(fth_buf, SYMBOL_END))) { 150 cmn_err(CE_CONT, "No %s in forthdebug\n", SYMBOL_END); 151 goto done; 152 } 153 *buf_p = '\0'; 154 #ifdef DEBUG 155 cmn_err(CE_CONT, "symbol lookup service (%ld bytes)\n", 156 (long)(buf_p - fth_buf)); 157 #endif /* DEBUG */ 158 prom_interpret(fth_buf, 0, 0, 0, 0, 0); 159 goto done; 160 } 161 162 cmn_err(CE_CONT, "%s (%d bytes) ", FDEBUGFILE, sz); 163 prom_interpret(fth_buf, 0, 0, 0, 0, 0); 164 cmn_err(CE_CONT, "loaded\n"); 165 obpdebug = 1; /* backward compatibility */ 166 167 if (forthdebug_dbp) { 168 #ifdef NO_KOBJ_NOTIFY 169 modsym = kobj_getsymvalue("kobj_notify_add", 0); 170 (void) ((int (*)(kobj_notify_list_t *))modsym)(&knl_load); 171 (void) ((int (*)(kobj_notify_list_t *))modsym)(&knl_unload); 172 #else 173 (void) kobj_notify_add(&knl_load); 174 (void) kobj_notify_add(&knl_unload); 175 #endif /* NO_KOBJ_NOTIFY */ 176 prom_interpret(INSTALL_DBP, 0, 0, 0, 0, 0); 177 debug_enter("Defer breakpoint enabled. Add breakpoints, then"); 178 } 179 done: 180 kobj_free(fth_buf, bstat.st_size + 1); 181 err_stat: 182 kobj_close_file(file); 183 184 if (boothowto & RB_HALT) 185 debug_enter("forthdebug: halt flag (-h) is set.\n"); 186 } 187