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