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 <mdb/mdb_debug.h>
30 #include <mdb/mdb_err.h>
31 #include <mdb/mdb_io.h>
32 #include <mdb/mdb_lex.h>
33 #include <mdb/mdb.h>
34
35 #include <libproc.h>
36 #include <libctf.h>
37 #include <rtld_db.h>
38 #include <strings.h>
39 #include <stdarg.h>
40
41 typedef struct dbg_mode {
42 const char *m_name;
43 const char *m_desc;
44 uint_t m_bits;
45 } dbg_mode_t;
46
47 static const dbg_mode_t dbg_modetab[] = {
48 { "cmdbuf", "debug command editing buffer", MDB_DBG_CMDBUF },
49 #ifdef YYDEBUG
50 { "parser", "debug parser internals", MDB_DBG_PARSER },
51 #endif
52 { "help", "display this listing", MDB_DBG_HELP },
53 { "module", "debug module processing", MDB_DBG_MODULE },
54 { "dcmd", "debug dcmd processing", MDB_DBG_DCMD },
55 { "elf", "debug ELF file processing", MDB_DBG_ELF },
56 { "mach", "debug machine-dependent code", MDB_DBG_MACH },
57 { "shell", "debug shell escapes", MDB_DBG_SHELL },
58 { "kmod", "debug kernel module processing", MDB_DBG_KMOD },
59 { "walk", "debug walk callback processing", MDB_DBG_WALK },
60 { "umem", "debug memory management", MDB_DBG_UMEM },
61 { "dstk", "debug execution stack", MDB_DBG_DSTK },
62 { "tgt", "debug target backends", MDB_DBG_TGT },
63 { "psvc", "debug proc_service clients", MDB_DBG_PSVC },
64 { "proc", "debug libproc internals", MDB_DBG_PROC },
65 { "ctf", "debug libctf internals", MDB_DBG_CTF },
66 { "dpi", "debugger/PROM interface (kmdb only)", MDB_DBG_DPI },
67 { "kdi", "kernel/debugger interface (kmdb only)", MDB_DBG_KDI },
68 { "callb", "debug callback invocations", MDB_DBG_CALLB },
69 { "all", "set all debug modes", (uint_t)~MDB_DBG_HELP },
70 { "none", "unset all debug modes", 0 },
71 { NULL, 0 }
72 };
73
74 static const char dbg_prefix[] = "mdb DEBUG: ";
75
76 /*PRINTFLIKE2*/
77 void
mdb_dprintf(uint_t mode,const char * format,...)78 mdb_dprintf(uint_t mode, const char *format, ...)
79 {
80 if ((mdb.m_debug & mode) == mode && mdb.m_err != NULL) {
81 va_list alist;
82
83 mdb_iob_puts(mdb.m_err, dbg_prefix);
84 va_start(alist, format);
85 mdb_iob_vprintf(mdb.m_err, format, alist);
86 va_end(alist);
87 }
88 }
89
90 void
mdb_dvprintf(uint_t mode,const char * format,va_list alist)91 mdb_dvprintf(uint_t mode, const char *format, va_list alist)
92 {
93 if ((mdb.m_debug & mode) == mode && format != NULL && *format != '\0' &&
94 mdb.m_err != NULL) {
95 mdb_iob_puts(mdb.m_err, dbg_prefix);
96 mdb_iob_vprintf(mdb.m_err, format, alist);
97 if (format[strlen(format) - 1] != '\n')
98 mdb_iob_nl(mdb.m_err);
99 }
100 }
101
102 uint_t
mdb_dstr2mode(const char * s)103 mdb_dstr2mode(const char *s)
104 {
105 const dbg_mode_t *mp;
106 const char *name;
107 char dstr[256];
108
109 uint_t bits = 0;
110
111 if (s == NULL)
112 return (0);
113
114 (void) strncpy(dstr, s, sizeof (dstr));
115 dstr[sizeof (dstr) - 1] = '\0';
116
117 for (name = strtok(dstr, ","); name; name = strtok(NULL, ",")) {
118 for (mp = dbg_modetab; mp->m_name != NULL; mp++) {
119 if (strcmp(name, mp->m_name) == 0) {
120 if (mp->m_bits != 0)
121 bits |= mp->m_bits;
122 else
123 bits = 0;
124 break;
125 }
126 }
127
128 if (mp->m_name == NULL)
129 warn("unknown debug option \"%s\"\n", name);
130 }
131
132 if (bits & MDB_DBG_HELP) {
133 warn("Debugging tokens:\n");
134 for (mp = dbg_modetab; mp->m_name != NULL; mp++)
135 warn("\t%s: %s\n", mp->m_name, mp->m_desc);
136 }
137
138 return (bits);
139 }
140
141 void
mdb_dmode(uint_t bits)142 mdb_dmode(uint_t bits)
143 {
144 int *libproc_debugp, *libctf_debugp;
145 void (*rd_logp)(const int);
146
147 if ((libproc_debugp = dlsym(RTLD_SELF, "_libproc_debug")) != NULL)
148 *libproc_debugp = (bits & MDB_DBG_PROC) != 0;
149
150 if ((libctf_debugp = dlsym(RTLD_SELF, "_libctf_debug")) != NULL)
151 *libctf_debugp = (bits & MDB_DBG_CTF) != 0;
152
153 if ((rd_logp = (void (*)())dlsym(RTLD_SELF, "rd_log")) != NULL)
154 rd_logp((bits & MDB_DBG_PSVC) != 0);
155
156 mdb_lex_debug(bits & MDB_DBG_PARSER);
157 mdb.m_debug = bits;
158 }
159
160 #ifdef DEBUG
161 int
mdb_dassert(const char * expr,const char * file,int line)162 mdb_dassert(const char *expr, const char *file, int line)
163 {
164 fail("\"%s\", line %d: assertion failed: %s\n", file, line, expr);
165 /*NOTREACHED*/
166 return (0);
167 }
168 #endif
169
170 /*
171 * Function to convert mdb longjmp codes (see <mdb/mdb.h>) into a string for
172 * debugging routines.
173 */
174 const char *
mdb_err2str(int err)175 mdb_err2str(int err)
176 {
177 static const char *const errtab[] = {
178 "0", "PARSE", "NOMEM", "PAGER", "SIGINT",
179 "QUIT", "ASSERT", "API", "ABORT", "OUTPUT"
180 };
181
182 static char buf[32];
183
184 if (err >= 0 && err < sizeof (errtab) / sizeof (errtab[0]))
185 return (errtab[err]);
186
187 (void) mdb_iob_snprintf(buf, sizeof (buf), "ERR#%d", err);
188 return (buf);
189 }
190