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