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 * isa-dependent portions of the kmdb target 31 */ 32 33 #include <kmdb/kvm.h> 34 #include <kmdb/kvm_cpu.h> 35 #include <kmdb/kmdb_kdi.h> 36 #include <kmdb/kmdb_asmutil.h> 37 #include <mdb/mdb_debug.h> 38 #include <mdb/mdb_err.h> 39 #include <mdb/mdb_list.h> 40 #include <mdb/mdb_target_impl.h> 41 #include <mdb/mdb_isautil.h> 42 #include <mdb/mdb_kreg_impl.h> 43 #include <mdb/mdb.h> 44 45 #include <sys/types.h> 46 #include <sys/frame.h> 47 #include <sys/trap.h> 48 #include <sys/bitmap.h> 49 50 /* Higher than the highest trap number for which we have a defined specifier */ 51 #define KMT_MAXTRAPNO 0x20 52 53 #define IOPORTLIMIT 0xffff /* XXX find a new home for this */ 54 55 const char * 56 kmt_def_dismode(void) 57 { 58 #ifdef __amd64 59 return ("amd64"); 60 #else 61 return ("ia32"); 62 #endif 63 } 64 65 int 66 kmt_step_out_validate(mdb_tgt_t *t, uintptr_t pc) 67 { 68 kmt_data_t *kmt = t->t_data; 69 int i; 70 71 for (i = 0; i < sizeof (kmt->kmt_intrsyms) / sizeof (GElf_Sym); i++) { 72 GElf_Sym *sym = (GElf_Sym *)&kmt->kmt_intrsyms + i; 73 74 if (pc >= sym->st_value && pc < sym->st_value + sym->st_size) 75 return (0); 76 } 77 78 return (1); 79 } 80 81 /* 82 * Determine the return address for the current frame. 83 */ 84 int 85 kmt_step_out(mdb_tgt_t *t, uintptr_t *p) 86 { 87 mdb_instr_t instr; 88 kreg_t pc, sp, fp; 89 90 (void) kmdb_dpi_get_register("pc", &pc); 91 (void) kmdb_dpi_get_register("sp", &sp); 92 (void) kmdb_dpi_get_register("fp", &fp); 93 94 if (mdb_tgt_vread(t, &instr, sizeof (mdb_instr_t), pc) != 95 sizeof (mdb_instr_t)) 96 return (-1); /* errno is set for us */ 97 98 if (!kmt_step_out_validate(t, pc)) 99 return (set_errno(EMDB_TGTNOTSUP)); 100 101 return (mdb_isa_step_out(t, p, pc, fp, sp, instr)); 102 } 103 104 int 105 kmt_step_branch(mdb_tgt_t *t) 106 { 107 kmt_data_t *kmt = t->t_data; 108 109 return (kmt_cpu_step_branch(t, kmt->kmt_cpu)); 110 } 111 112 /* 113 * Return the address of the next instruction following a call, or return -1 114 * and set errno to EAGAIN if the target should just single-step. 115 */ 116 int 117 kmt_next(mdb_tgt_t *t, uintptr_t *p) 118 { 119 kreg_t pc; 120 mdb_instr_t instr; 121 122 (void) kmdb_dpi_get_register("pc", &pc); 123 124 if (mdb_tgt_vread(t, &instr, sizeof (mdb_instr_t), pc) != 125 sizeof (mdb_instr_t)) 126 return (-1); /* errno is set for us */ 127 128 return (mdb_isa_next(t, p, pc, instr)); 129 } 130 131 /* 132 * Return a flag indicating if the specified %eip is likely to have an 133 * interrupt frame on the stack. We do this by comparing the address to the 134 * range of addresses spanned by several well-known routines, and looking 135 * to see if the next and previous %ebp values are "far" apart. Sigh. 136 */ 137 int 138 mdb_kvm_intrframe(mdb_tgt_t *t, uintptr_t pc, uintptr_t fp, 139 uintptr_t prevfp) 140 { 141 kmt_data_t *kmt = t->t_data; 142 const size_t dist = 0x800 * sizeof (uintptr_t); 143 144 return ((pc >= kmt->kmt_cmnint.st_value && 145 (pc < kmt->kmt_cmnint.st_value + kmt->kmt_cmnint.st_size)) || 146 (pc >= kmt->kmt_cmntrap.st_value && 147 (pc < kmt->kmt_cmntrap.st_value + kmt->kmt_cmntrap.st_size)) || 148 (fp >= prevfp + dist) || (fp <= prevfp - dist)); 149 } 150 151 /*ARGSUSED*/ 152 static int 153 kmt_stack_common(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv, 154 int cpuid, mdb_tgt_stack_f *func) 155 { 156 const mdb_tgt_gregset_t *grp = NULL; 157 mdb_tgt_gregset_t gregs; 158 void *arg = (void *)(uintptr_t)mdb.m_nargs; 159 160 if (flags & DCMD_ADDRSPEC) { 161 bzero(&gregs, sizeof (gregs)); 162 gregs.kregs[KREG_FP] = addr; 163 grp = &gregs; 164 } else 165 grp = kmdb_dpi_get_gregs(cpuid); 166 167 if (argc != 0) { 168 if (argv->a_type == MDB_TYPE_CHAR || argc > 1) 169 return (DCMD_USAGE); 170 171 if (argv->a_type == MDB_TYPE_STRING) 172 arg = (void *)(uintptr_t)mdb_strtoull(argv->a_un.a_str); 173 else 174 arg = (void *)(uintptr_t)argv->a_un.a_val; 175 } 176 177 (void) mdb_isa_kvm_stack_iter(mdb.m_target, grp, func, arg); 178 179 return (DCMD_OK); 180 } 181 182 int 183 kmt_cpustack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv, 184 int cpuid, int verbose) 185 { 186 return (kmt_stack_common(addr, flags, argc, argv, cpuid, 187 (verbose ? mdb_isa_kvm_framev : mdb_isa_kvm_frame))); 188 } 189 190 int 191 kmt_stack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 192 { 193 return (kmt_stack_common(addr, flags, argc, argv, DPI_MASTER_CPUID, 194 mdb_isa_kvm_frame)); 195 } 196 197 int 198 kmt_stackv(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 199 { 200 return (kmt_stack_common(addr, flags, argc, argv, DPI_MASTER_CPUID, 201 mdb_isa_kvm_framev)); 202 } 203 204 int 205 kmt_stackr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 206 { 207 return (kmt_stack_common(addr, flags, argc, argv, DPI_MASTER_CPUID, 208 mdb_isa_kvm_framev)); 209 } 210 211 /*ARGSUSED*/ 212 void 213 kmt_printregs(const mdb_tgt_gregset_t *gregs) 214 { 215 mdb_isa_printregs(gregs); 216 } 217 218 #define IOCHECK_NOWARN 0 219 #define IOCHECK_WARN 1 220 221 static int 222 kmt_io_check(uint64_t nbytes, uintptr_t addr, int dowarn) 223 { 224 if (addr > IOPORTLIMIT) { 225 if (dowarn) 226 warn("port address must be 0-%#x\n", IOPORTLIMIT); 227 return (set_errno(EINVAL)); 228 } 229 230 if (nbytes != 1 && nbytes != 2 && nbytes != 4) { 231 if (dowarn) 232 warn("port access must be 1, 2, or 4 bytes\n"); 233 return (set_errno(EINVAL)); 234 } 235 236 if ((addr & (nbytes - 1)) != 0) { 237 if (dowarn) { 238 warn("address for %llu-byte access must be %llu-byte " 239 "aligned\n", (u_longlong_t)nbytes, 240 (u_longlong_t)nbytes); 241 } 242 return (set_errno(EINVAL)); 243 } 244 245 return (0); 246 } 247 248 /*ARGSUSED1*/ 249 int 250 kmt_in_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 251 { 252 uint64_t len = 0; 253 uint32_t buf; 254 255 if (mdb_getopts(argc, argv, 256 'L', MDB_OPT_UINT64, &len, 257 NULL) != argc) 258 return (DCMD_USAGE); 259 260 if (len == 0) 261 len = mdb.m_dcount; 262 263 if (kmt_io_check(len, addr, IOCHECK_WARN) < 0) 264 return (DCMD_ERR); 265 266 if (mdb_tgt_ioread(mdb.m_target, &buf, len, addr) < 0) { 267 warn("failed to read from port 0x%llx", (u_longlong_t)addr); 268 return (DCMD_ERR); 269 } 270 271 mdb_printf("%x\n", buf); 272 273 return (DCMD_OK); 274 } 275 276 /*ARGSUSED1*/ 277 int 278 kmt_out_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 279 { 280 uint64_t len = 0; 281 uint64_t val; 282 283 if (mdb_getopts(argc, argv, 284 'L', MDB_OPT_UINT64, &len, 285 NULL) != argc - 1) 286 return (DCMD_USAGE); 287 288 if (len == 0) 289 len = mdb.m_dcount; 290 291 argv += argc - 1; 292 if (argv->a_type == MDB_TYPE_STRING) 293 val = mdb_strtoull(argv->a_un.a_str); 294 else 295 val = argv->a_un.a_val; 296 297 if (kmt_io_check(len, addr, IOCHECK_WARN) < 0) 298 return (DCMD_ERR); 299 300 if (val > (1ULL << (len * NBBY)) - 1) { 301 warn("value is out of range for port size\n"); 302 return (DCMD_ERR); 303 } 304 305 if (mdb_tgt_iowrite(mdb.m_target, &val, len, addr) < 0) { 306 warn("failed to write to port %llx", (u_longlong_t)addr); 307 return (DCMD_ERR); 308 } 309 310 return (DCMD_OK); 311 } 312 313 static int 314 kmt_rwmsr(uint32_t addr, uint64_t *valp, void (*rw)(uint32_t, uint64_t *)) 315 { 316 jmp_buf pcb, *oldpcb = NULL; 317 318 if (setjmp(pcb) != 0) { 319 kmdb_dpi_restore_fault_hdlr(oldpcb); 320 return (-1); /* errno is set for us */ 321 } 322 323 oldpcb = kmdb_dpi_set_fault_hdlr(&pcb); 324 rw(addr, valp); 325 kmdb_dpi_restore_fault_hdlr(oldpcb); 326 327 return (0); 328 } 329 330 /*ARGSUSED*/ 331 int 332 kmt_rdmsr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 333 { 334 uint64_t val; 335 336 if (!(flags & DCMD_ADDRSPEC)) 337 return (DCMD_USAGE); 338 339 if (kmt_rwmsr(addr, &val, rdmsr) < 0) { 340 warn("rdmsr failed"); 341 return (DCMD_ERR); 342 } 343 344 mdb_printf("%llx\n", (u_longlong_t)val); 345 346 return (DCMD_OK); 347 } 348 349 /*ARGSUSED*/ 350 int 351 kmt_wrmsr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 352 { 353 uint64_t val; 354 355 if (!(flags & DCMD_ADDRSPEC) || argc != 1) 356 return (DCMD_USAGE); 357 358 if (argv->a_type == MDB_TYPE_STRING) 359 val = mdb_strtoull(argv->a_un.a_str); 360 else 361 val = argv->a_un.a_val; 362 363 if (kmt_rwmsr(addr, &val, wrmsr)) { 364 warn("wrmsr failed"); 365 return (DCMD_ERR); 366 } 367 368 return (DCMD_OK); 369 } 370 371 int 372 kmt_msr_validate(const kmdb_msr_t *msr) 373 { 374 uint64_t val; 375 376 for (/* */; msr->msr_num != 0; msr++) { 377 if (kmt_rwmsr(msr->msr_num, &val, rdmsr) < 0) 378 return (0); 379 } 380 381 return (1); 382 } 383 384 /*ARGSUSED*/ 385 ssize_t 386 kmt_write(mdb_tgt_t *t, const void *buf, size_t nbytes, uintptr_t addr) 387 { 388 if (!(t->t_flags & MDB_TGT_F_ALLOWIO) && 389 (nbytes = kmdb_kdi_range_is_nontoxic(addr, nbytes, 1)) == 0) 390 return (set_errno(EMDB_NOMAP)); 391 392 return (kmt_rw(t, (void *)buf, nbytes, addr, kmt_writer)); 393 } 394 395 /*ARGSUSED*/ 396 static ssize_t 397 kmt_iorw(mdb_tgt_t *t, void *buf, size_t nbytes, uint64_t addr, 398 void (*iorw)(void *, size_t, uintptr_t)) 399 { 400 jmp_buf pcb, *oldpcb = NULL; 401 402 if (kmt_io_check(nbytes, addr, IOCHECK_NOWARN) < 0) 403 return (-1); /* errno is set for us */ 404 405 if (setjmp(pcb) != 0) { 406 kmdb_dpi_restore_fault_hdlr(oldpcb); 407 return (-1); /* errno is set for us */ 408 } 409 410 oldpcb = kmdb_dpi_set_fault_hdlr(&pcb); 411 iorw(buf, nbytes, addr); 412 kmdb_dpi_restore_fault_hdlr(oldpcb); 413 414 return (nbytes); 415 } 416 417 /*ARGSUSED*/ 418 ssize_t 419 kmt_ioread(mdb_tgt_t *t, void *buf, size_t nbytes, uintptr_t addr) 420 { 421 return (kmt_iorw(t, buf, nbytes, addr, kmt_in)); 422 } 423 424 /*ARGSUSED*/ 425 ssize_t 426 kmt_iowrite(mdb_tgt_t *t, const void *buf, size_t nbytes, uintptr_t addr) 427 { 428 return (kmt_iorw(t, (void *)buf, nbytes, addr, kmt_out)); 429 } 430 431 const char * 432 kmt_trapname(int trapnum) 433 { 434 static char trapname[11]; 435 436 switch (trapnum) { 437 case T_ZERODIV: 438 return ("division by zero (#de) trap"); 439 case T_SGLSTP: 440 return ("single-step (#db) trap"); 441 case T_NMIFLT: 442 return ("NMI"); 443 case T_BPTFLT: 444 return ("breakpoint (#bp) trap"); 445 case T_ILLINST: 446 return ("illegal instruction (#ud) trap"); 447 case T_SEGFLT: 448 return ("segment not present (#np) trap"); 449 case T_STKFLT: 450 return ("stack (#ss) trap"); 451 case T_GPFLT: 452 return ("general protection (#gp) trap"); 453 case T_PGFLT: 454 return ("page fault (#pf) trap"); 455 case T_ALIGNMENT: 456 return ("alignment check (#ac) trap"); 457 case T_MCE: 458 return ("machine check (#mc) trap"); 459 case T_SIMDFPE: 460 return ("SSE/SSE2 (#xm) trap"); 461 case T_DBGENTR: 462 return ("debugger entry trap"); 463 default: 464 (void) mdb_snprintf(trapname, sizeof (trapname), "trap %#x", 465 trapnum); 466 return (trapname); 467 } 468 } 469 470 void 471 kmt_init_isadep(mdb_tgt_t *t) 472 { 473 kmt_data_t *kmt = t->t_data; 474 475 kmt->kmt_rds = mdb_isa_kregs; 476 477 kmt->kmt_trapmax = KMT_MAXTRAPNO; 478 kmt->kmt_trapmap = mdb_zalloc(BT_SIZEOFMAP(kmt->kmt_trapmax), UM_SLEEP); 479 480 /* Traps for which we want to provide an explicit message */ 481 (void) mdb_tgt_add_fault(t, T_ZERODIV, MDB_TGT_SPEC_INTERNAL, 482 no_se_f, NULL); 483 (void) mdb_tgt_add_fault(t, T_ILLINST, MDB_TGT_SPEC_INTERNAL, 484 no_se_f, NULL); 485 (void) mdb_tgt_add_fault(t, T_SEGFLT, MDB_TGT_SPEC_INTERNAL, 486 no_se_f, NULL); 487 (void) mdb_tgt_add_fault(t, T_STKFLT, MDB_TGT_SPEC_INTERNAL, 488 no_se_f, NULL); 489 (void) mdb_tgt_add_fault(t, T_GPFLT, MDB_TGT_SPEC_INTERNAL, 490 no_se_f, NULL); 491 (void) mdb_tgt_add_fault(t, T_PGFLT, MDB_TGT_SPEC_INTERNAL, 492 no_se_f, NULL); 493 (void) mdb_tgt_add_fault(t, T_ALIGNMENT, MDB_TGT_SPEC_INTERNAL, 494 no_se_f, NULL); 495 (void) mdb_tgt_add_fault(t, T_MCE, MDB_TGT_SPEC_INTERNAL, 496 no_se_f, NULL); 497 (void) mdb_tgt_add_fault(t, T_SIMDFPE, MDB_TGT_SPEC_INTERNAL, 498 no_se_f, NULL); 499 500 /* 501 * Traps which will be handled elsewhere, and which therefore don't 502 * need the trap-based message. 503 */ 504 BT_SET(kmt->kmt_trapmap, T_SGLSTP); 505 BT_SET(kmt->kmt_trapmap, T_BPTFLT); 506 BT_SET(kmt->kmt_trapmap, T_DBGENTR); 507 508 /* Catch-all for traps not explicitly listed here */ 509 (void) mdb_tgt_add_fault(t, KMT_TRAP_NOTENUM, MDB_TGT_SPEC_INTERNAL, 510 no_se_f, NULL); 511 } 512 513 void 514 kmt_startup_isadep(mdb_tgt_t *t) 515 { 516 kmt_data_t *kmt = t->t_data; 517 518 /* 519 * The stack trace and ::step out code need to detect "interrupt" 520 * frames. The heuristic they use to detect said frames requires the 521 * addresses of routines that can generate them. 522 */ 523 (void) mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC, 524 "cmnint", &kmt->kmt_intrsyms._kmt_cmnint, NULL); 525 (void) mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC, 526 "cmntrap", &kmt->kmt_intrsyms._kmt_cmntrap, NULL); 527 (void) mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC, 528 "sys_sysenter", &kmt->kmt_intrsyms._kmt_sysenter, NULL); 529 #if defined(__amd64) 530 (void) mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC, 531 "sys_syscall", &kmt->kmt_intrsyms._kmt_syscall, NULL); 532 #endif 533 } 534