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