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
fdbp_hook()75 static void fdbp_hook() {} /* null function for defer breakpoint operation */
76
77 /*ARGSUSED*/
fdbp_snoop(unsigned int i,struct modctl * modctl_p)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
forthdebug_init(void)94 forthdebug_init(void)
95 {
96 char *fth_buf, *buf_p;
97 ulong_t modsym;
98 int i, sz;
99 uint64_t fsz;
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 = kobj_get_filesize(file, &fsz);
117 if (i || !fsz) {
118 cmn_err(CE_CONT, "Can't stat %s stat=%x sz=%llx\n",
119 FDEBUGFILE, i, (long long)fsz);
120 goto err_stat;
121 }
122
123 fth_buf = (char *)kobj_zalloc(fsz + 1, KM_SLEEP);
124 sz = kobj_read_file(file, fth_buf, fsz, 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(fsz == 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, fsz + 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