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 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * MDB Regression Test Module 29 * 30 * This module contains dcmds and walkers that exercise various aspects of 31 * MDB and the MDB Module API. It can be manually loaded and executed to 32 * verify that MDB is still working properly. 33 */ 34 35 #include <mdb/mdb_modapi.h> 36 #define _MDB 37 #include <mdb/mdb_io_impl.h> 38 #include <mdb/mdb.h> 39 #undef _MDB 40 41 static int 42 cd_init(mdb_walk_state_t *wsp) 43 { 44 wsp->walk_addr = 0xf; 45 return (WALK_NEXT); 46 } 47 48 static int 49 cd_step(mdb_walk_state_t *wsp) 50 { 51 int status = wsp->walk_callback(wsp->walk_addr, NULL, wsp->walk_cbdata); 52 53 if (wsp->walk_addr-- == 0) 54 return (WALK_DONE); 55 56 return (status); 57 } 58 59 /*ARGSUSED*/ 60 static int 61 cmd_praddr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 62 { 63 if ((flags != (DCMD_ADDRSPEC|DCMD_LOOP|DCMD_PIPE)) && 64 (flags != (DCMD_ADDRSPEC|DCMD_LOOP|DCMD_PIPE|DCMD_LOOPFIRST))) { 65 mdb_warn("ERROR: praddr invoked with flags = 0x%x\n", flags); 66 return (DCMD_ERR); 67 } 68 69 if (argc != 0) { 70 mdb_warn("ERROR: praddr invoked with argc = %lu\n", argc); 71 return (DCMD_ERR); 72 } 73 74 mdb_printf("%lr\n", addr); 75 return (DCMD_OK); 76 } 77 78 static int 79 compare(const void *lp, const void *rp) 80 { 81 uintptr_t lhs = *((const uintptr_t *)lp); 82 uintptr_t rhs = *((const uintptr_t *)rp); 83 return (lhs - rhs); 84 } 85 86 /*ARGSUSED*/ 87 static int 88 cmd_qsort(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 89 { 90 mdb_pipe_t p; 91 size_t i; 92 93 if (flags != (DCMD_ADDRSPEC | DCMD_LOOP | 94 DCMD_LOOPFIRST | DCMD_PIPE | DCMD_PIPE_OUT)) { 95 mdb_warn("ERROR: qsort invoked with flags = 0x%x\n", flags); 96 return (DCMD_ERR); 97 } 98 99 if (argc != 0) { 100 mdb_warn("ERROR: qsort invoked with argc = %lu\n", argc); 101 return (DCMD_ERR); 102 } 103 104 mdb_get_pipe(&p); 105 106 if (p.pipe_data == NULL || p.pipe_len != 16) { 107 mdb_warn("ERROR: qsort got bad results from mdb_get_pipe\n"); 108 return (DCMD_ERR); 109 } 110 111 if (p.pipe_data[0] != addr) { 112 mdb_warn("ERROR: qsort pipe_data[0] != addr\n"); 113 return (DCMD_ERR); 114 } 115 116 qsort(p.pipe_data, p.pipe_len, sizeof (uintptr_t), compare); 117 mdb_set_pipe(&p); 118 119 for (i = 0; i < 16; i++) { 120 if (p.pipe_data[i] != i) { 121 mdb_warn("ERROR: qsort got bad data in slot %lu\n", i); 122 return (DCMD_ERR); 123 } 124 } 125 126 return (DCMD_OK); 127 } 128 129 /*ARGSUSED*/ 130 static int 131 cmd_runtest(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 132 { 133 mdb_walker_t w = { "count", "count", cd_init, cd_step, NULL }; 134 int state, i; 135 136 mdb_printf("- adding countdown walker\n"); 137 if (mdb_add_walker(&w) != 0) { 138 mdb_warn("ERROR: failed to add walker"); 139 return (DCMD_ERR); 140 } 141 142 mdb_printf("- executing countdown pipeline\n"); 143 if (mdb_eval("::walk mdb_test`count |::mdb_test`qsort |::praddr")) { 144 mdb_warn("ERROR: failed to eval command"); 145 return (DCMD_ERR); 146 } 147 148 mdb_printf("- removing countdown walker\n"); 149 if (mdb_remove_walker("count") != 0) { 150 mdb_warn("ERROR: failed to remove walker"); 151 return (DCMD_ERR); 152 } 153 154 state = mdb_get_state(); 155 mdb_printf("- kernel=%d state=%d\n", mdb_prop_kernel, state); 156 157 if (mdb_prop_kernel && (state == MDB_STATE_DEAD || 158 state == MDB_STATE_RUNNING)) { 159 mdb_printf("- exercising pipelines\n"); 160 for (i = 0; i < 100; i++) { 161 if (mdb_eval("::walk proc p | ::map *. | ::grep .==0 " 162 "| ::map <p | ::ps") != 0) { 163 mdb_warn("ERROR: failed to eval pipeline"); 164 return (DCMD_ERR); 165 } 166 } 167 } 168 169 return (DCMD_OK); 170 } 171 172 static int 173 cmd_vread(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 174 { 175 size_t nbytes; 176 ssize_t rbytes; 177 void *buf; 178 179 if (!(flags & DCMD_ADDRSPEC) || argc != 1) 180 return (DCMD_USAGE); 181 182 if (argv->a_type == MDB_TYPE_STRING) 183 nbytes = (size_t)mdb_strtoull(argv->a_un.a_str); 184 else 185 nbytes = (size_t)argv->a_un.a_val; 186 187 buf = mdb_alloc(nbytes, UM_SLEEP | UM_GC); 188 rbytes = mdb_vread(buf, nbytes, addr); 189 190 if (rbytes >= 0) { 191 mdb_printf("mdb_vread of %lu bytes returned %ld\n", 192 nbytes, rbytes); 193 } else 194 mdb_warn("mdb_vread returned %ld", rbytes); 195 196 return (DCMD_OK); 197 } 198 199 /*ARGSUSED*/ 200 static int 201 cmd_pread(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 202 { 203 size_t nbytes; 204 ssize_t rbytes; 205 void *buf; 206 207 if (!(flags & DCMD_ADDRSPEC) || argc != 1) 208 return (DCMD_USAGE); 209 210 if (argv->a_type == MDB_TYPE_STRING) 211 nbytes = (size_t)mdb_strtoull(argv->a_un.a_str); 212 else 213 nbytes = (size_t)argv->a_un.a_val; 214 215 buf = mdb_alloc(nbytes, UM_SLEEP | UM_GC); 216 rbytes = mdb_pread(buf, nbytes, mdb_get_dot()); 217 218 if (rbytes >= 0) { 219 mdb_printf("mdb_pread of %lu bytes returned %ld\n", 220 nbytes, rbytes); 221 } else 222 mdb_warn("mdb_pread returned %ld", rbytes); 223 224 return (DCMD_OK); 225 } 226 227 /*ARGSUSED*/ 228 static int 229 cmd_readsym(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 230 { 231 size_t nbytes; 232 ssize_t rbytes; 233 void *buf; 234 235 if ((flags & DCMD_ADDRSPEC) || argc != 2 || 236 argv->a_type != MDB_TYPE_STRING) 237 return (DCMD_USAGE); 238 239 if (argv[1].a_type == MDB_TYPE_STRING) 240 nbytes = (size_t)mdb_strtoull(argv[1].a_un.a_str); 241 else 242 nbytes = (size_t)argv[1].a_un.a_val; 243 244 buf = mdb_alloc(nbytes, UM_SLEEP | UM_GC); 245 rbytes = mdb_readsym(buf, nbytes, argv->a_un.a_str); 246 247 if (rbytes >= 0) { 248 mdb_printf("mdb_readsym of %lu bytes returned %ld\n", 249 nbytes, rbytes); 250 } else 251 mdb_warn("mdb_readsym returned %ld", rbytes); 252 253 return (DCMD_OK); 254 } 255 256 static int 257 cmd_call_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 258 { 259 const char *dcmd; 260 261 if (argc < 1 || argv->a_type != MDB_TYPE_STRING) 262 return (DCMD_USAGE); 263 264 dcmd = argv->a_un.a_str; 265 argv++; 266 argc--; 267 268 if (mdb_call_dcmd(dcmd, addr, flags, argc, argv) == -1) { 269 mdb_warn("failed to execute %s", dcmd); 270 return (DCMD_ERR); 271 } 272 273 return (DCMD_OK); 274 } 275 276 /*ARGSUSED*/ 277 static int 278 cmd_getsetdot(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 279 { 280 if (argc != 0) 281 return (DCMD_USAGE); 282 283 mdb_set_dot(0x12345678feedbeefULL); 284 285 if (mdb_get_dot() != 0x12345678feedbeefULL) { 286 mdb_warn("mdb_get_dot() returned wrong value!\n"); 287 return (DCMD_ERR); 288 } 289 290 return (DCMD_OK); 291 } 292 293 /* 294 * kmdb doesn't export some of the symbols used by these tests - namely mdb and 295 * mdb_iob_.*. We therefore can't use these tests with kmdb. 296 */ 297 #ifndef _KMDB 298 static void 299 do_nputs_tests(const char *banner, uint_t flags, 300 size_t rows, size_t cols, size_t ocols) 301 { 302 uint_t oflags; 303 int i; 304 305 oflags = mdb_iob_getflags(mdb.m_out) & 306 (MDB_IOB_AUTOWRAP | MDB_IOB_INDENT); 307 308 mdb_printf("%s:\n", banner); 309 for (i = 0; i < 8; i++) 310 mdb_printf("0123456789"); 311 mdb_printf("\n"); 312 313 mdb_iob_clrflags(mdb.m_out, MDB_IOB_AUTOWRAP | MDB_IOB_INDENT); 314 mdb_iob_setflags(mdb.m_out, flags); 315 mdb_iob_resize(mdb.m_out, rows, cols); 316 317 for (i = 0; i < 50; i++) 318 mdb_printf(" xx"); 319 mdb_printf("\n"); 320 321 mdb_iob_clrflags(mdb.m_out, flags); 322 mdb_iob_setflags(mdb.m_out, oflags); 323 mdb_iob_resize(mdb.m_out, rows, ocols); 324 } 325 326 /*ARGSUSED*/ 327 static int 328 cmd_nputs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 329 { 330 size_t rows = mdb.m_out->iob_rows; 331 size_t cols = mdb.m_out->iob_cols; 332 333 if (argc != 0) 334 return (DCMD_USAGE); 335 336 if (!(flags & DCMD_ADDRSPEC)) 337 addr = cols; 338 339 do_nputs_tests("tests with (~WRAP, ~INDENT)", 340 0, rows, addr, cols); 341 342 do_nputs_tests("tests with (WRAP, ~INDENT)", 343 MDB_IOB_AUTOWRAP, rows, addr, cols); 344 345 do_nputs_tests("tests with (~WRAP, INDENT)", 346 MDB_IOB_INDENT, rows, addr, cols); 347 348 do_nputs_tests("tests with (WRAP, INDENT)", 349 MDB_IOB_AUTOWRAP | MDB_IOB_INDENT, rows, addr, cols); 350 351 return (DCMD_OK); 352 } 353 #endif 354 355 /*ARGSUSED*/ 356 static int 357 cmd_printf(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 358 { 359 if (argc != 2 || argv[0].a_type != MDB_TYPE_STRING) 360 return (DCMD_USAGE); 361 362 if (argv[1].a_type == MDB_TYPE_STRING) 363 mdb_printf(argv[0].a_un.a_str, argv[1].a_un.a_str); 364 else 365 mdb_printf(argv[0].a_un.a_str, argv[1].a_un.a_val); 366 367 return (DCMD_OK); 368 } 369 370 /*ARGSUSED*/ 371 static int 372 cmd_abort(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 373 { 374 mdb_printf("hello"); /* stuff something in stdout's buffer */ 375 return (*((volatile int *)NULL)); 376 } 377 378 static const mdb_dcmd_t dcmds[] = { 379 { "runtest", NULL, "run MDB regression tests", cmd_runtest }, 380 { "qsort", NULL, "qsort addresses", cmd_qsort }, 381 { "praddr", NULL, "print addresses", cmd_praddr }, 382 { "vread", ":nbytes", "call mdb_vread", cmd_vread }, 383 { "pread", ":nbytes", "call mdb_pread", cmd_pread }, 384 { "readsym", "symbol nbytes", "call mdb_readsym", cmd_readsym }, 385 { "call_dcmd", "dcmd [ args ... ]", "call dcmd", cmd_call_dcmd }, 386 { "getsetdot", NULL, "test get and set dot", cmd_getsetdot }, 387 #ifndef _KMDB 388 { "nputs", "?", "test iob nputs engine", cmd_nputs }, 389 #endif 390 { "printf", "fmt arg", "test printf engine", cmd_printf }, 391 { "abort", NULL, "test unexpected dcmd abort", cmd_abort }, 392 { NULL } 393 }; 394 395 static const mdb_walker_t walkers[] = { 396 { "countdown", "count down from 16 to 0", cd_init, cd_step, NULL }, 397 { NULL } 398 }; 399 400 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers }; 401 402 const mdb_modinfo_t * 403 _mdb_init(void) 404 { 405 return (&modinfo); 406 } 407