1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2019 Joyent, Inc. 14 */ 15 16 /* 17 * bhyve target 18 * 19 * The bhyve target is used to examine and manipulate a bhyve VM. Access to 20 * a bhyve VM is provided by libvmm, which itself uses libvmmapi, which uses 21 * the vmm driver's ioctl interface to carry out requests. 22 * 23 * The bhyve target does not know about threads or processes, but it handles 24 * multiple vCPUs and can switch between them. Execution control is currently 25 * limited to completely stopping or resuming all vCPUs of a VM, or single- 26 * stepping a particular vCPU while all other vCPUs remain stopped. Breakpoints 27 * are not implemented yet, and as such step-out and step-over don't work yet. 28 * All known x86 instruction sets are support, legacy IA-16, IA-32 and AMD64. 29 * The current CPU instruction set is automatically determined by parsing the 30 * code segment (CS) attributes in the current vCPU. 31 * 32 * All of the VMs physical memory and device memory segments are mapped R/W 33 * into mdb's address space by libvmm. All accesses to those memory are 34 * facilitated through libvmm calls, which may include virtual address 35 * translation according to the current vCPU mode. Both real-mode and protected- 36 * mode segmentation are understood and used for translating virtual addresses 37 * into linear addresses, which may further be translated using 2-level, 3-level 38 * or 4-level paging. 39 * 40 * To handle disassembly and stack tracing properly when segmentation is used by 41 * a vCPU (always in real mode, sometimes in protected mode) the bhyve target 42 * has a notion of three virtual address spaces used for reading/writing memory: 43 * - MDB_TGT_AS_VIRT, the default virtual address space uses the DS segment 44 * by default, but this default can be changed with the ::defseg dcmd. 45 * - MDB_TGT_AS_VIRT_I, the virtual address space for instructions always 46 * uses the code segment (CS) for translation 47 * - MDB_TGT_AS_VIRT_S, the virtual address space for the stack always uses 48 * the stack segment (SS) for translation 49 * 50 * Register printing and stack tracing is using the common x86 ISA-specific code 51 * in IA-32 and AMD64 modes. There is no stack tracing for IA-16 mode yet. 52 * 53 * Todo: 54 * - support for breakpoint, step-out, and step-over 55 * - support for x86 stack tracing 56 */ 57 #include <mdb/mdb_conf.h> 58 #include <mdb/mdb_err.h> 59 #include <mdb/mdb_signal.h> 60 #include <mdb/mdb_modapi.h> 61 #include <mdb/mdb_io_impl.h> 62 #include <mdb/mdb_kreg_impl.h> 63 #include <mdb/mdb_target_impl.h> 64 #include <mdb/mdb_isautil.h> 65 #include <mdb/mdb_amd64util.h> 66 #include <mdb/mdb_ia32util.h> 67 #include <mdb/mdb_x86util.h> 68 #include <mdb/mdb.h> 69 70 #include <sys/controlregs.h> 71 #include <sys/debugreg.h> 72 #include <sys/sysmacros.h> 73 #include <sys/note.h> 74 #include <unistd.h> 75 #include <inttypes.h> 76 77 #include <libvmm.h> 78 79 #define MDB_DEF_PROMPT "[%<_cpuid>]> " 80 81 typedef struct bhyve_data { 82 vmm_t *bd_vmm; 83 uint_t bd_curcpu; 84 int bd_defseg; 85 86 /* must be last */ 87 char bd_name[]; 88 } bhyve_data_t; 89 90 91 const mdb_tgt_regdesc_t bhyve_kregs[] = { 92 { "rdi", KREG_RDI, MDB_TGT_R_EXPORT }, 93 { "edi", KREG_RDI, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 94 { "di", KREG_RDI, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 95 { "dil", KREG_RDI, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 96 { "rsi", KREG_RSI, MDB_TGT_R_EXPORT }, 97 { "esi", KREG_RSI, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 98 { "si", KREG_RSI, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 99 { "sil", KREG_RSI, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 100 { "rdx", KREG_RDX, MDB_TGT_R_EXPORT }, 101 { "edx", KREG_RDX, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 102 { "dx", KREG_RDX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 103 { "dh", KREG_RDX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H }, 104 { "dl", KREG_RDX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 105 { "rcx", KREG_RCX, MDB_TGT_R_EXPORT }, 106 { "ecx", KREG_RCX, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 107 { "cx", KREG_RCX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 108 { "ch", KREG_RCX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H }, 109 { "cl", KREG_RCX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 110 { "r8", KREG_R8, MDB_TGT_R_EXPORT }, 111 { "r8d", KREG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 112 { "r8w", KREG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 113 { "r8l", KREG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 114 { "r9", KREG_R9, MDB_TGT_R_EXPORT }, 115 { "r9d", KREG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 116 { "r9w", KREG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 117 { "r9l", KREG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 118 { "rax", KREG_RAX, MDB_TGT_R_EXPORT }, 119 { "eax", KREG_RAX, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 120 { "ax", KREG_RAX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 121 { "ah", KREG_RAX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H }, 122 { "al", KREG_RAX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 123 { "rbx", KREG_RBX, MDB_TGT_R_EXPORT }, 124 { "ebx", KREG_RBX, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 125 { "bx", KREG_RBX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 126 { "bh", KREG_RBX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H }, 127 { "bl", KREG_RBX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 128 { "rbp", KREG_RBP, MDB_TGT_R_EXPORT }, 129 { "ebp", KREG_RBP, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 130 { "bp", KREG_RBP, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 131 { "bpl", KREG_RBP, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 132 { "r10", KREG_R10, MDB_TGT_R_EXPORT }, 133 { "r10d", KREG_R10, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 134 { "r10w", KREG_R10, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 135 { "r10l", KREG_R10, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 136 { "r11", KREG_R11, MDB_TGT_R_EXPORT }, 137 { "r11d", KREG_R11, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 138 { "r11w", KREG_R11, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 139 { "r11l", KREG_R11, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 140 { "r12", KREG_R12, MDB_TGT_R_EXPORT }, 141 { "r12d", KREG_R12, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 142 { "r12w", KREG_R12, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 143 { "r12l", KREG_R12, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 144 { "r13", KREG_R13, MDB_TGT_R_EXPORT }, 145 { "r13d", KREG_R13, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 146 { "r13w", KREG_R13, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 147 { "r13l", KREG_R13, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 148 { "r14", KREG_R14, MDB_TGT_R_EXPORT }, 149 { "r14d", KREG_R14, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 150 { "r14w", KREG_R14, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 151 { "r14l", KREG_R14, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 152 { "r15", KREG_R15, MDB_TGT_R_EXPORT }, 153 { "r15d", KREG_R15, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 154 { "r15w", KREG_R15, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 155 { "r15l", KREG_R15, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 156 { "ds", KREG_DS, MDB_TGT_R_EXPORT }, 157 { "es", KREG_ES, MDB_TGT_R_EXPORT }, 158 { "fs", KREG_FS, MDB_TGT_R_EXPORT }, 159 { "gs", KREG_GS, MDB_TGT_R_EXPORT }, 160 { "rip", KREG_RIP, MDB_TGT_R_EXPORT }, 161 { "cs", KREG_CS, MDB_TGT_R_EXPORT }, 162 { "rflags", KREG_RFLAGS, MDB_TGT_R_EXPORT }, 163 { "eflags", KREG_RFLAGS, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 164 { "rsp", KREG_RSP, MDB_TGT_R_EXPORT }, 165 { "esp", KREG_RSP, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 166 { "sp", KREG_RSP, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 167 { "spl", KREG_RSP, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 168 { "ss", KREG_SS, MDB_TGT_R_EXPORT }, 169 { "cr2", KREG_CR2, MDB_TGT_R_EXPORT }, 170 { "cr3", KREG_CR3, MDB_TGT_R_EXPORT }, 171 { NULL, 0, 0 } 172 }; 173 174 static const char *segments[] = { "CS", "DS", "ES", "FS", "GS", "SS" }; 175 176 177 /*ARGSUSED*/ 178 static uintmax_t 179 bhyve_cpuid_get(const mdb_var_t *v) 180 { 181 bhyve_data_t *bd = mdb.m_target->t_data; 182 183 return (bd->bd_curcpu); 184 } 185 186 static const mdb_nv_disc_t bhyve_cpuid_disc = { 187 .disc_get = bhyve_cpuid_get 188 }; 189 190 191 static uintmax_t 192 bhyve_reg_get(const mdb_var_t *v) 193 { 194 mdb_tgt_reg_t r = 0; 195 196 if (mdb_tgt_getareg(MDB_NV_COOKIE(v), 0, mdb_nv_get_name(v), &r) == -1) 197 mdb_warn("failed to get %%%s register", mdb_nv_get_name(v)); 198 199 return (r); 200 } 201 202 static void 203 bhyve_reg_set(mdb_var_t *v, uintmax_t r) 204 { 205 if (mdb_tgt_putareg(MDB_NV_COOKIE(v), 0, mdb_nv_get_name(v), r) == -1) 206 mdb_warn("failed to modify %%%s register", mdb_nv_get_name(v)); 207 } 208 209 static const mdb_nv_disc_t bhyve_reg_disc = { 210 .disc_set = bhyve_reg_set, 211 .disc_get = bhyve_reg_get 212 }; 213 214 static int 215 bhyve_get_gregset(bhyve_data_t *bd, int cpu, mdb_tgt_gregset_t *gregs) 216 { 217 vmm_desc_t fs, gs; 218 219 /* 220 * Register numbers to get, the order must match the definitions of 221 * KREG_* in mdb_kreg.h so that we get a proper mdb_tgt_gregset_t 222 * that the register printing functions will understand. 223 * 224 * There are a few fields in mdb_tgt_gregset_t that can't be accessed 225 * with vmm_get_regset(), either because they don't exist in bhyve or 226 * or because they need to be accessed with vmm_get_desc(). For these 227 * cases we ask for RAX instead and fill it with 0 or the real value, 228 * respectively. 229 */ 230 static const int regnums[] = { 231 KREG_RAX, /* dummy for SAVFP */ 232 KREG_RAX, /* dummy for SAVFP */ 233 KREG_RDI, 234 KREG_RSI, 235 KREG_RDX, 236 KREG_RCX, 237 KREG_R8, 238 KREG_R9, 239 KREG_RAX, 240 KREG_RBX, 241 KREG_RBP, 242 KREG_R10, 243 KREG_R11, 244 KREG_R12, 245 KREG_R13, 246 KREG_R14, 247 KREG_R15, 248 KREG_RAX, /* dummy for FSBASE */ 249 KREG_RAX, /* dummy for GSBASE */ 250 KREG_RAX, /* dummy for KGSBASE */ 251 KREG_CR2, 252 KREG_CR3, 253 KREG_DS, 254 KREG_ES, 255 KREG_FS, 256 KREG_GS, 257 KREG_RAX, /* dummy for TRAPNO */ 258 KREG_RAX, /* dummy for ERR */ 259 KREG_RIP, 260 KREG_CS, 261 KREG_RFLAGS, 262 KREG_RSP, 263 KREG_SS 264 }; 265 266 if (vmm_get_regset(bd->bd_vmm, cpu, KREG_NGREG, regnums, 267 &gregs->kregs[0]) != 0) { 268 mdb_warn("failed to get general-purpose registers for CPU %d", 269 cpu); 270 return (-1); 271 } 272 273 if (vmm_get_desc(bd->bd_vmm, cpu, VMM_DESC_FS, &fs) != 0 || 274 vmm_get_desc(bd->bd_vmm, cpu, VMM_DESC_GS, &gs) != 0) { 275 mdb_warn("failed to get FS/GS descriptors for CPU %d", cpu); 276 return (-1); 277 } 278 279 gregs->kregs[KREG_SAVFP] = 0; 280 gregs->kregs[KREG_SAVPC] = 0; 281 gregs->kregs[KREG_KGSBASE] = 0; 282 gregs->kregs[KREG_TRAPNO] = 0; 283 gregs->kregs[KREG_ERR] = 0; 284 285 gregs->kregs[KREG_FSBASE] = fs.vd_base; 286 gregs->kregs[KREG_GSBASE] = gs.vd_base; 287 288 return (0); 289 } 290 291 static int 292 bhyve_cpuregs_dcmd(uintptr_t addr, uint_t flags, int argc, 293 const mdb_arg_t *argv) 294 { 295 bhyve_data_t *bd = mdb.m_target->t_data; 296 uint64_t cpu = bd->bd_curcpu; 297 mdb_tgt_gregset_t gregs; 298 int i; 299 300 301 if (flags & DCMD_ADDRSPEC) { 302 if (argc != 0) 303 return (DCMD_USAGE); 304 305 cpu = (uint64_t)addr; 306 } 307 308 i = mdb_getopts(argc, argv, 'c', MDB_OPT_UINT64, &cpu, NULL); 309 310 argc -= i; 311 argv += i; 312 313 if (argc != 0) 314 return (DCMD_USAGE); 315 316 if (cpu >= vmm_ncpu(bd->bd_vmm)) { 317 mdb_warn("no such CPU\n"); 318 return (DCMD_ERR); 319 } 320 321 if (bhyve_get_gregset(bd, cpu, &gregs) != 0) 322 return (DCMD_ERR); 323 324 325 switch (vmm_vcpu_isa(bd->bd_vmm, cpu)) { 326 case VMM_ISA_64: 327 mdb_amd64_printregs(&gregs); 328 break; 329 case VMM_ISA_32: 330 case VMM_ISA_16: 331 mdb_ia32_printregs(&gregs); 332 break; 333 default: 334 mdb_warn("CPU %d mode unknown", cpu); 335 return (DCMD_ERR); 336 } 337 338 return (0); 339 } 340 341 static int 342 bhyve_regs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 343 { 344 if ((flags & DCMD_ADDRSPEC) || argc != 0) 345 return (DCMD_USAGE); 346 347 return (bhyve_cpuregs_dcmd(addr, flags, argc, argv)); 348 } 349 350 static int 351 bhyve_stack_common(uintptr_t addr, uint_t flags, int argc, 352 const mdb_arg_t *argv, int vcpu, boolean_t verbose) 353 { 354 bhyve_data_t *bd = mdb.m_target->t_data; 355 void *arg = (void *)(uintptr_t)mdb.m_nargs; 356 357 mdb_tgt_gregset_t gregs; 358 mdb_tgt_stack_f *func; 359 360 if (vcpu == -1) 361 vcpu = bd->bd_curcpu; 362 363 if (flags & DCMD_ADDRSPEC) { 364 bzero(&gregs, sizeof (gregs)); 365 gregs.kregs[KREG_RBP] = addr; 366 } else if (bhyve_get_gregset(bd, vcpu, &gregs) != 0) 367 return (DCMD_ERR); 368 369 switch (vmm_vcpu_isa(bd->bd_vmm, vcpu)) { 370 case VMM_ISA_64: 371 func = verbose ? mdb_amd64_kvm_framev : mdb_amd64_kvm_frame; 372 (void) mdb_amd64_kvm_stack_iter(mdb.m_target, &gregs, func, 373 arg); 374 break; 375 case VMM_ISA_32: 376 func = verbose ? mdb_ia32_kvm_framev : mdb_amd64_kvm_frame; 377 (void) mdb_ia32_kvm_stack_iter(mdb.m_target, &gregs, func, arg); 378 break; 379 case VMM_ISA_16: 380 mdb_warn("IA16 stack tracing not implemented\n"); 381 return (DCMD_ERR); 382 default: 383 mdb_warn("CPU %d mode unknown", vcpu); 384 return (DCMD_ERR); 385 } 386 387 return (DCMD_OK); 388 } 389 390 static int 391 bhyve_cpustack_dcmd(uintptr_t addr, uint_t flags, int argc, 392 const mdb_arg_t *argv) 393 { 394 bhyve_data_t *bd = mdb.m_target->t_data; 395 uint64_t cpu = bd->bd_curcpu; 396 boolean_t verbose; 397 int i; 398 399 if (flags & DCMD_ADDRSPEC) { 400 if (argc != 0) 401 return (DCMD_USAGE); 402 403 if (addr < vmm_ncpu(bd->bd_vmm)) { 404 cpu = (uint64_t)addr; 405 flags &= ~DCMD_ADDRSPEC; 406 } 407 } 408 409 i = mdb_getopts(argc, argv, 410 'c', MDB_OPT_UINT64, &cpu, 411 'v', MDB_OPT_SETBITS, 1, &verbose, 412 NULL); 413 414 argc -= i; 415 argv += i; 416 417 if (argc != 0) 418 return (DCMD_USAGE); 419 420 return (bhyve_stack_common(addr, flags, argc, argv, cpu, verbose)); 421 } 422 423 static int 424 bhyve_stack_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 425 { 426 return (bhyve_stack_common(addr, flags, argc, argv, -1, B_FALSE)); 427 } 428 429 static int 430 bhyve_stackv_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 431 { 432 return (bhyve_stack_common(addr, flags, argc, argv, -1, B_TRUE)); 433 } 434 435 static int 436 bhyve_stackr_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 437 { 438 return (bhyve_stack_common(addr, flags, argc, argv, -1, B_TRUE)); 439 } 440 441 static int 442 bhyve_status_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 443 { 444 bhyve_data_t *bd = mdb.m_target->t_data; 445 vmm_mode_t mode; 446 vmm_isa_t isa; 447 448 static const char *modes[] = { 449 "unknown mode", 450 "real mode", 451 "protected mode, no PAE", 452 "protected mode, PAE", 453 "long mode" 454 }; 455 static const char *isas[] = { 456 "unknown ISA", 457 "IA16", 458 "IA32", 459 "AMD64" 460 }; 461 462 if ((flags & DCMD_ADDRSPEC) || argc != 0) 463 return (DCMD_USAGE); 464 465 mode = vmm_vcpu_mode(bd->bd_vmm, bd->bd_curcpu); 466 isa = vmm_vcpu_isa(bd->bd_vmm, bd->bd_curcpu); 467 468 mdb_printf("debugging live VM '%s'\n", bd->bd_name); 469 mdb_printf("VM memory size: %d MB\n", 470 vmm_memsize(bd->bd_vmm) / 1024 / 1024); 471 mdb_printf("vCPUs: %d\n", vmm_ncpu(bd->bd_vmm)); 472 mdb_printf("current CPU: %d (%s, %s)\n", bd->bd_curcpu, modes[mode], 473 isas[isa]); 474 mdb_printf("default segment: %s", 475 segments[bd->bd_defseg - VMM_DESC_CS]); 476 477 return (DCMD_OK); 478 } 479 480 481 static int 482 bhyve_sysregs_dcmd(uintptr_t addr, uint_t flags, int argc, 483 const mdb_arg_t *argv) 484 { 485 bhyve_data_t *bd = mdb.m_target->t_data; 486 uint64_t cpu = bd->bd_curcpu; 487 int ret = DCMD_ERR; 488 struct sysregs sregs; 489 int i; 490 491 /* 492 * This array must use the order of the elements of struct sysregs. 493 */ 494 static const int regnums[] = { 495 VMM_REG_CR0, 496 VMM_REG_CR2, 497 VMM_REG_CR3, 498 VMM_REG_CR4, 499 VMM_REG_DR0, 500 VMM_REG_DR1, 501 VMM_REG_DR2, 502 VMM_REG_DR3, 503 VMM_REG_DR6, 504 VMM_REG_DR7, 505 VMM_REG_EFER, 506 VMM_REG_PDPTE0, 507 VMM_REG_PDPTE1, 508 VMM_REG_PDPTE2, 509 VMM_REG_PDPTE3, 510 VMM_REG_INTR_SHADOW 511 }; 512 513 if (flags & DCMD_ADDRSPEC) { 514 if (argc != 0) 515 return (DCMD_USAGE); 516 517 cpu = (uint64_t)addr; 518 } 519 520 i = mdb_getopts(argc, argv, 'c', MDB_OPT_UINT64, &cpu, NULL); 521 522 argc -= i; 523 argv += i; 524 525 if (argc != 0) 526 return (DCMD_USAGE); 527 528 if (cpu >= vmm_ncpu(bd->bd_vmm)) { 529 mdb_warn("no such CPU\n"); 530 return (DCMD_ERR); 531 } 532 533 if (vmm_get_regset(bd->bd_vmm, cpu, ARRAY_SIZE(regnums), regnums, 534 (uint64_t *)&sregs) != 0) 535 goto fail; 536 537 if (vmm_get_desc(bd->bd_vmm, cpu, VMM_DESC_GDTR, 538 (vmm_desc_t *)&sregs.sr_gdtr) != 0 || 539 vmm_get_desc(bd->bd_vmm, cpu, VMM_DESC_IDTR, 540 (vmm_desc_t *)&sregs.sr_idtr) != 0 || 541 vmm_get_desc(bd->bd_vmm, cpu, VMM_DESC_LDTR, 542 (vmm_desc_t *)&sregs.sr_ldtr) != 0 || 543 vmm_get_desc(bd->bd_vmm, cpu, VMM_DESC_TR, 544 (vmm_desc_t *)&sregs.sr_tr) != 0 || 545 vmm_get_desc(bd->bd_vmm, cpu, VMM_DESC_CS, 546 (vmm_desc_t *)&sregs.sr_cs) != 0 || 547 vmm_get_desc(bd->bd_vmm, cpu, VMM_DESC_DS, 548 (vmm_desc_t *)&sregs.sr_ds) != 0 || 549 vmm_get_desc(bd->bd_vmm, cpu, VMM_DESC_ES, 550 (vmm_desc_t *)&sregs.sr_es) != 0 || 551 vmm_get_desc(bd->bd_vmm, cpu, VMM_DESC_FS, 552 (vmm_desc_t *)&sregs.sr_fs) != 0 || 553 vmm_get_desc(bd->bd_vmm, cpu, VMM_DESC_GS, 554 (vmm_desc_t *)&sregs.sr_gs) != 0 || 555 vmm_get_desc(bd->bd_vmm, cpu, VMM_DESC_SS, 556 (vmm_desc_t *)&sregs.sr_ss) != 0) 557 goto fail; 558 559 mdb_x86_print_sysregs(&sregs, vmm_vcpu_mode(bd->bd_vmm, cpu) == 560 VMM_MODE_LONG); 561 562 ret = DCMD_OK; 563 564 fail: 565 if (ret != DCMD_OK) 566 mdb_warn("failed to get system registers for CPU %d\n", cpu); 567 return (ret); 568 } 569 570 static int 571 bhyve_dbgregs_dcmd(uintptr_t addr, uint_t flags, int argc, 572 const mdb_arg_t *argv) 573 { 574 bhyve_data_t *bd = mdb.m_target->t_data; 575 uint64_t cpu = bd->bd_curcpu; 576 int ret = DCMD_ERR; 577 vmm_desc_t gdtr, ldtr, idtr, tr, cs, ds, es, fs, gs, ss; 578 uint64_t *regvals; 579 int i; 580 581 /* 582 * This array must use the order of definitions set in libvmm.h 583 * to make GETREG() work. 584 */ 585 #define GETREG(r) (regvals[r - VMM_REG_DR0]) 586 static const int regnums[] = { 587 VMM_REG_DR0, 588 VMM_REG_DR1, 589 VMM_REG_DR2, 590 VMM_REG_DR3, 591 VMM_REG_DR6, 592 VMM_REG_DR7, 593 }; 594 595 static const mdb_bitmask_t dr6_flag_bits[] = { 596 { "DR0", DR_TRAP0, DR_TRAP0 }, 597 { "DR1", DR_TRAP1, DR_TRAP1 }, 598 { "DR2", DR_TRAP2, DR_TRAP2 }, 599 { "DR3", DR_TRAP3, DR_TRAP3 }, 600 { "debug reg", DR_ICEALSO, DR_ICEALSO }, 601 { "single step", DR_SINGLESTEP, DR_SINGLESTEP }, 602 { "task switch", DR_TASKSWITCH, DR_TASKSWITCH }, 603 { NULL, 0, 0 } 604 }; 605 606 #define DR_RW(x, m) \ 607 ((DR_RW_MASK & (m)) << (DR_CONTROL_SHIFT + (x) * DR_CONTROL_SIZE)) 608 #define DR_LEN(x, m) \ 609 ((DR_LEN_MASK & (m)) << (DR_CONTROL_SHIFT + (x) * DR_CONTROL_SIZE)) 610 611 static const mdb_bitmask_t dr7_flag_bits[] = { 612 { "L0", DR_ENABLE0, DR_LOCAL_ENABLE_MASK & DR_ENABLE0 }, 613 { "G0", DR_ENABLE0, DR_GLOBAL_ENABLE_MASK & DR_ENABLE0 }, 614 { "L1", DR_ENABLE1, DR_LOCAL_ENABLE_MASK & DR_ENABLE1 }, 615 { "G1", DR_ENABLE1, DR_GLOBAL_ENABLE_MASK & DR_ENABLE1 }, 616 { "L2", DR_ENABLE2, DR_LOCAL_ENABLE_MASK & DR_ENABLE2 }, 617 { "G2", DR_ENABLE2, DR_GLOBAL_ENABLE_MASK & DR_ENABLE2 }, 618 { "L3", DR_ENABLE3, DR_LOCAL_ENABLE_MASK & DR_ENABLE3 }, 619 { "G3", DR_ENABLE3, DR_GLOBAL_ENABLE_MASK & DR_ENABLE3 }, 620 { "LE", DR_LOCAL_SLOWDOWN, DR_LOCAL_SLOWDOWN }, 621 { "GE", DR_GLOBAL_SLOWDOWN, DR_GLOBAL_SLOWDOWN }, 622 { "RTM", DR_RTM, DR_RTM }, 623 { "GD", DR_GENERAL_DETECT, DR_GENERAL_DETECT }, 624 { "0:X", DR_RW(0, DR_RW_MASK), DR_RW(0, DR_RW_EXECUTE) }, 625 { "0:W", DR_RW(0, DR_RW_MASK), DR_RW(0, DR_RW_WRITE) }, 626 { "0:IO", DR_RW(0, DR_RW_MASK), DR_RW(0, DR_RW_IO_RW) }, 627 { "0:RW", DR_RW(0, DR_RW_MASK), DR_RW(0, DR_RW_READ) }, 628 { "1:X", DR_RW(1, DR_RW_MASK), DR_RW(1, DR_RW_EXECUTE) }, 629 { "1:W", DR_RW(1, DR_RW_MASK), DR_RW(1, DR_RW_WRITE) }, 630 { "1:IO", DR_RW(1, DR_RW_MASK), DR_RW(1, DR_RW_IO_RW) }, 631 { "1:RW", DR_RW(1, DR_RW_MASK), DR_RW(1, DR_RW_READ) }, 632 { "2:X", DR_RW(2, DR_RW_MASK), DR_RW(2, DR_RW_EXECUTE) }, 633 { "2:W", DR_RW(2, DR_RW_MASK), DR_RW(2, DR_RW_WRITE) }, 634 { "2:IO", DR_RW(2, DR_RW_MASK), DR_RW(2, DR_RW_IO_RW) }, 635 { "2:RW", DR_RW(2, DR_RW_MASK), DR_RW(2, DR_RW_READ) }, 636 { "3:X", DR_RW(3, DR_RW_MASK), DR_RW(3, DR_RW_EXECUTE) }, 637 { "3:W", DR_RW(3, DR_RW_MASK), DR_RW(3, DR_RW_WRITE) }, 638 { "3:IO", DR_RW(3, DR_RW_MASK), DR_RW(3, DR_RW_IO_RW) }, 639 { "3:RW", DR_RW(3, DR_RW_MASK), DR_RW(3, DR_RW_READ) }, 640 { "0:1", DR_LEN(0, DR_LEN_MASK), DR_LEN(0, DR_LEN_1) }, 641 { "0:2", DR_LEN(0, DR_LEN_MASK), DR_LEN(0, DR_LEN_2) }, 642 { "0:4", DR_LEN(0, DR_LEN_MASK), DR_LEN(0, DR_LEN_4) }, 643 { "0:8", DR_LEN(0, DR_LEN_MASK), DR_LEN(0, DR_LEN_8) }, 644 { "1:1", DR_LEN(1, DR_LEN_MASK), DR_LEN(1, DR_LEN_1) }, 645 { "1:2", DR_LEN(1, DR_LEN_MASK), DR_LEN(1, DR_LEN_2) }, 646 { "1:4", DR_LEN(1, DR_LEN_MASK), DR_LEN(1, DR_LEN_4) }, 647 { "1:8", DR_LEN(1, DR_LEN_MASK), DR_LEN(1, DR_LEN_8) }, 648 { "2:1", DR_LEN(2, DR_LEN_MASK), DR_LEN(2, DR_LEN_1) }, 649 { "2:2", DR_LEN(2, DR_LEN_MASK), DR_LEN(2, DR_LEN_2) }, 650 { "2:4", DR_LEN(2, DR_LEN_MASK), DR_LEN(2, DR_LEN_4) }, 651 { "2:8", DR_LEN(2, DR_LEN_MASK), DR_LEN(2, DR_LEN_8) }, 652 { "3:1", DR_LEN(3, DR_LEN_MASK), DR_LEN(3, DR_LEN_1) }, 653 { "3:2", DR_LEN(3, DR_LEN_MASK), DR_LEN(3, DR_LEN_2) }, 654 { "3:4", DR_LEN(3, DR_LEN_MASK), DR_LEN(3, DR_LEN_4) }, 655 { "3:8", DR_LEN(3, DR_LEN_MASK), DR_LEN(3, DR_LEN_8) }, 656 { NULL, 0, 0 }, 657 }; 658 659 660 if (flags & DCMD_ADDRSPEC) { 661 if (argc != 0) 662 return (DCMD_USAGE); 663 664 cpu = (uint64_t)addr; 665 } 666 667 i = mdb_getopts(argc, argv, 'c', MDB_OPT_UINT64, &cpu, NULL); 668 669 argc -= i; 670 argv += i; 671 672 if (argc != 0) 673 return (DCMD_USAGE); 674 675 if (cpu >= vmm_ncpu(bd->bd_vmm)) { 676 mdb_warn("no such CPU\n"); 677 return (DCMD_ERR); 678 } 679 680 regvals = mdb_zalloc(ARRAY_SIZE(regnums) * sizeof (uint64_t), UM_SLEEP); 681 682 if (vmm_get_regset(bd->bd_vmm, cpu, ARRAY_SIZE(regnums), regnums, 683 regvals) != 0) 684 goto fail; 685 686 mdb_printf("%%dr0 = 0x%0?p %A\n", 687 GETREG(VMM_REG_DR0), GETREG(VMM_REG_DR0)); 688 mdb_printf("%%dr1 = 0x%0?p %A\n", 689 GETREG(VMM_REG_DR1), GETREG(VMM_REG_DR1)); 690 mdb_printf("%%dr2 = 0x%0?p %A\n", 691 GETREG(VMM_REG_DR2), GETREG(VMM_REG_DR2)); 692 mdb_printf("%%dr3 = 0x%0?p %A\n", 693 GETREG(VMM_REG_DR3), GETREG(VMM_REG_DR3)); 694 mdb_printf("%%dr6 = 0x%0lx <%b>\n", 695 GETREG(VMM_REG_DR6), GETREG(VMM_REG_DR6), dr6_flag_bits); 696 mdb_printf("%%dr7 = 0x%0lx <%b>\n", 697 GETREG(VMM_REG_DR7), GETREG(VMM_REG_DR7), dr7_flag_bits); 698 #undef GETREG 699 700 ret = DCMD_OK; 701 702 fail: 703 if (ret != DCMD_OK) 704 mdb_warn("failed to get debug registers for CPU %d\n", cpu); 705 mdb_free(regvals, ARRAY_SIZE(regnums) * sizeof (uint64_t)); 706 return (ret); 707 } 708 709 static int 710 bhyve_switch_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 711 { 712 bhyve_data_t *bd = mdb.m_target->t_data; 713 size_t cpu = (int)addr; 714 715 if (!(flags & DCMD_ADDRSPEC) || argc != 0) 716 return (DCMD_USAGE); 717 718 if (cpu >= vmm_ncpu(bd->bd_vmm)) { 719 mdb_warn("no such CPU\n"); 720 return (DCMD_ERR); 721 } 722 723 bd->bd_curcpu = cpu; 724 return (DCMD_OK); 725 726 } 727 728 static int 729 bhyve_seg2reg(const char *seg) 730 { 731 if (strcasecmp(seg, "cs") == 0) 732 return (VMM_DESC_CS); 733 else if (strcasecmp(seg, "ds") == 0) 734 return (VMM_DESC_DS); 735 else if (strcasecmp(seg, "es") == 0) 736 return (VMM_DESC_ES); 737 else if (strcasecmp(seg, "fs") == 0) 738 return (VMM_DESC_FS); 739 else if (strcasecmp(seg, "gs") == 0) 740 return (VMM_DESC_GS); 741 else if (strcasecmp(seg, "ss") == 0) 742 return (VMM_DESC_SS); 743 else 744 return (-1); 745 } 746 747 static int 748 bhyve_vtol_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 749 { 750 bhyve_data_t *bd = mdb.m_target->t_data; 751 int segreg = bd->bd_defseg; 752 char *seg = ""; 753 uint64_t laddr; 754 int i; 755 756 if (!(flags & DCMD_ADDRSPEC)) 757 return (DCMD_USAGE); 758 759 i = mdb_getopts(argc, argv, 's', MDB_OPT_STR, &seg, NULL); 760 761 argc -= i; 762 argv += i; 763 764 if (i != 0) { 765 if (argc != 0) 766 return (DCMD_USAGE); 767 768 segreg = bhyve_seg2reg(seg); 769 if (segreg == -1) 770 return (DCMD_USAGE); 771 } 772 773 if (vmm_vtol(bd->bd_vmm, bd->bd_curcpu, segreg, addr, &laddr) != 0) { 774 if (errno == EFAULT) 775 (void) set_errno(EMDB_NOMAP); 776 return (DCMD_ERR); 777 } 778 779 if (flags & DCMD_PIPE_OUT) 780 mdb_printf("%llr\n", laddr); 781 else 782 mdb_printf("virtual %lr mapped to linear %llr\n", addr, laddr); 783 784 return (DCMD_OK); 785 } 786 787 static int 788 bhyve_vtop_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 789 { 790 bhyve_data_t *bd = mdb.m_target->t_data; 791 int segreg = bd->bd_defseg; 792 char *seg = ""; 793 physaddr_t pa; 794 int i; 795 796 if (!(flags & DCMD_ADDRSPEC)) 797 return (DCMD_USAGE); 798 799 i = mdb_getopts(argc, argv, 's', MDB_OPT_STR, &seg, NULL); 800 801 argc -= i; 802 argv += i; 803 804 if (i != 0) { 805 segreg = bhyve_seg2reg(seg); 806 if (segreg == -1) 807 return (DCMD_USAGE); 808 } 809 810 if (vmm_vtop(bd->bd_vmm, bd->bd_curcpu, segreg, addr, &pa) == -1) { 811 mdb_warn("failed to get physical mapping"); 812 return (DCMD_ERR); 813 } 814 815 if (flags & DCMD_PIPE_OUT) 816 mdb_printf("%llr\n", pa); 817 else 818 mdb_printf("virtual %lr mapped to physical %llr\n", addr, pa); 819 return (DCMD_OK); 820 } 821 822 static int 823 bhyve_defseg_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 824 { 825 bhyve_data_t *bd = mdb.m_target->t_data; 826 int segreg = bd->bd_defseg; 827 char *seg = ""; 828 int i; 829 830 if (flags & DCMD_ADDRSPEC) 831 return (DCMD_USAGE); 832 833 i = mdb_getopts(argc, argv, 's', MDB_OPT_STR, &seg, NULL); 834 835 argc -= i; 836 argv += i; 837 838 if (i != 0) { 839 if (argc != 0) 840 return (DCMD_USAGE); 841 842 segreg = bhyve_seg2reg(seg); 843 if (segreg == -1) 844 return (DCMD_USAGE); 845 846 bd->bd_defseg = segreg; 847 } 848 849 mdb_printf("using segment %s for virtual to linear address translation", 850 segments[bd->bd_defseg - VMM_DESC_CS]); 851 852 return (DCMD_OK); 853 } 854 855 static const mdb_dcmd_t bhyve_dcmds[] = { 856 { "$c", NULL, "print stack backtrace", bhyve_stack_dcmd }, 857 { "$C", NULL, "print stack backtrace", bhyve_stackv_dcmd }, 858 { "$r", NULL, "print general-purpose registers", bhyve_regs_dcmd }, 859 { "$?", NULL, "print status and registers", bhyve_regs_dcmd }, 860 { ":x", ":", "change the active CPU", bhyve_switch_dcmd }, 861 { "cpustack", "?[-v] [-c cpuid] [cnt]", "print stack backtrace for a " 862 "specific CPU", bhyve_cpustack_dcmd }, 863 { "cpuregs", "?[-c cpuid]", "print general-purpose registers for a " 864 "specific CPU", bhyve_cpuregs_dcmd }, 865 { "dbgregs", "?[-c cpuid]", "print debug registers for a specific CPU", 866 bhyve_dbgregs_dcmd }, 867 { "defseg", "?[-s segment]", "change the default segment used to " 868 "translate addresses", bhyve_defseg_dcmd }, 869 { "regs", NULL, "print general-purpose registers", bhyve_regs_dcmd }, 870 { "stack", NULL, "print stack backtrace", bhyve_stack_dcmd }, 871 { "stackregs", NULL, "print stack backtrace and registers", 872 bhyve_stackr_dcmd }, 873 { "status", NULL, "print summary of current target", 874 bhyve_status_dcmd }, 875 { "sysregs", "?[-c cpuid]", "print system registers for a specific CPU", 876 bhyve_sysregs_dcmd }, 877 { "switch", ":", "change the active CPU", bhyve_switch_dcmd }, 878 { "vtol", ":[-s segment]", "print linear mapping of virtual address", 879 bhyve_vtol_dcmd }, 880 { "vtop", ":[-s segment]", "print physical mapping of virtual " 881 "address", bhyve_vtop_dcmd }, 882 { NULL } 883 }; 884 885 886 /* 887 * t_setflags: change target flags 888 */ 889 static int 890 bhyve_setflags(mdb_tgt_t *tgt, int flags) 891 { 892 bhyve_data_t *bd = tgt->t_data; 893 894 if (((tgt->t_flags ^ flags) & MDB_TGT_F_RDWR) != 0) { 895 boolean_t writable = (flags & MDB_TGT_F_RDWR) != 0; 896 897 vmm_unmap(bd->bd_vmm); 898 if (vmm_map(bd->bd_vmm, writable) != 0) { 899 mdb_warn("failed to map guest memory"); 900 return (set_errno(EMDB_TGT)); 901 } 902 } 903 904 tgt->t_flags = flags; 905 906 return (0); 907 } 908 909 /* 910 * t_activate: activate target 911 */ 912 static void 913 bhyve_activate(mdb_tgt_t *tgt) 914 { 915 mdb_tgt_status_t *tsp = &tgt->t_status; 916 bhyve_data_t *bd = tgt->t_data; 917 const char *format; 918 char buf[BUFSIZ]; 919 920 (void) mdb_set_prompt(MDB_DEF_PROMPT); 921 922 (void) mdb_tgt_register_dcmds(tgt, bhyve_dcmds, MDB_MOD_FORCE); 923 mdb_tgt_register_regvars(tgt, bhyve_kregs, &bhyve_reg_disc, 0); 924 925 (void) vmm_stop(bd->bd_vmm); 926 927 if (mdb_tgt_status(tgt, tsp) != 0) 928 return; 929 930 if (tsp->st_pc != 0) { 931 if (mdb_dis_ins2str(mdb.m_disasm, mdb.m_target, 932 MDB_TGT_AS_VIRT_I, buf, sizeof (buf), tsp->st_pc) != 933 tsp->st_pc) 934 format = "target stopped at:\n%-#16a%8T%s\n"; 935 else 936 format = "target stopped at %a:\n"; 937 mdb_warn(format, tsp->st_pc, buf); 938 } 939 } 940 941 /* 942 * t_deactivate: deactivate target 943 */ 944 static void 945 bhyve_deactivate(mdb_tgt_t *tgt) 946 { 947 bhyve_data_t *bd = tgt->t_data; 948 const mdb_tgt_regdesc_t *rd; 949 const mdb_dcmd_t *dc; 950 951 for (rd = bhyve_kregs; rd->rd_name != NULL; rd++) { 952 mdb_var_t *var; 953 954 if (!(rd->rd_flags & MDB_TGT_R_EXPORT)) 955 continue; /* didn't export register as variable */ 956 957 if ((var = mdb_nv_lookup(&mdb.m_nv, rd->rd_name)) != NULL) { 958 var->v_flags &= ~MDB_NV_PERSIST; 959 mdb_nv_remove(&mdb.m_nv, var); 960 } 961 } 962 963 for (dc = bhyve_dcmds; dc->dc_name != NULL; dc++) 964 if (mdb_module_remove_dcmd(tgt->t_module, dc->dc_name) == -1) 965 mdb_warn("failed to remove dcmd %s", dc->dc_name); 966 967 (void) vmm_cont(bd->bd_vmm); 968 } 969 970 /* 971 * t_name: return name of target 972 */ 973 static const char * 974 bhyve_name(mdb_tgt_t *tgt) 975 { 976 _NOTE(ARGUNUSED(tgt)); 977 978 return ("bhyve"); 979 } 980 981 /* 982 * t_destroy: cleanup target private resources 983 */ 984 static void 985 bhyve_destroy(mdb_tgt_t *tgt) 986 { 987 bhyve_data_t *bd = tgt->t_data; 988 989 (void) vmm_cont(bd->bd_vmm); 990 vmm_unmap(bd->bd_vmm); 991 vmm_close_vm(bd->bd_vmm); 992 mdb_free(bd, sizeof (bhyve_data_t)); 993 tgt->t_data = NULL; 994 } 995 996 /* 997 * t_isa: return name of target ISA 998 */ 999 const char * 1000 bhyve_isa(mdb_tgt_t *tgt) 1001 { 1002 _NOTE(ARGUNUSED(tgt)); 1003 1004 return ("amd64"); 1005 } 1006 1007 /* 1008 * t_dmodel: return target data model 1009 */ 1010 static int 1011 bhyve_dmodel(mdb_tgt_t *tgt) 1012 { 1013 _NOTE(ARGUNUSED(tgt)); 1014 1015 return (MDB_TGT_MODEL_LP64); 1016 } 1017 1018 /*ARGSUSED*/ 1019 static ssize_t 1020 bhyve_aread(mdb_tgt_t *tgt, mdb_tgt_as_t as, void *buf, size_t nbytes, 1021 mdb_tgt_addr_t addr) 1022 { 1023 bhyve_data_t *bd = tgt->t_data; 1024 ssize_t cnt; 1025 1026 switch ((uintptr_t)as) { 1027 case (uintptr_t)MDB_TGT_AS_VIRT: 1028 cnt = vmm_vread(bd->bd_vmm, bd->bd_curcpu, bd->bd_defseg, buf, 1029 nbytes, addr); 1030 break; 1031 1032 case (uintptr_t)MDB_TGT_AS_VIRT_I: 1033 cnt = vmm_vread(bd->bd_vmm, bd->bd_curcpu, VMM_DESC_CS, buf, 1034 nbytes, addr); 1035 break; 1036 1037 case (uintptr_t)MDB_TGT_AS_VIRT_S: 1038 cnt = vmm_vread(bd->bd_vmm, bd->bd_curcpu, VMM_DESC_SS, buf, 1039 nbytes, addr); 1040 break; 1041 1042 case (uintptr_t)MDB_TGT_AS_PHYS: 1043 cnt = vmm_pread(bd->bd_vmm, buf, nbytes, addr); 1044 break; 1045 1046 case (uintptr_t)MDB_TGT_AS_FILE: 1047 case (uintptr_t)MDB_TGT_AS_IO: 1048 return (set_errno(EMDB_TGTNOTSUP)); 1049 } 1050 1051 if (errno == EFAULT) 1052 return (set_errno(EMDB_NOMAP)); 1053 1054 return (cnt); 1055 } 1056 1057 /*ARGSUSED*/ 1058 static ssize_t 1059 bhyve_awrite(mdb_tgt_t *tgt, mdb_tgt_as_t as, const void *buf, size_t nbytes, 1060 mdb_tgt_addr_t addr) 1061 { 1062 bhyve_data_t *bd = tgt->t_data; 1063 ssize_t cnt; 1064 1065 switch ((uintptr_t)as) { 1066 case (uintptr_t)MDB_TGT_AS_VIRT: 1067 cnt = vmm_vwrite(bd->bd_vmm, bd->bd_curcpu, bd->bd_defseg, buf, 1068 nbytes, addr); 1069 break; 1070 1071 case (uintptr_t)MDB_TGT_AS_VIRT_I: 1072 cnt = vmm_vwrite(bd->bd_vmm, bd->bd_curcpu, VMM_DESC_CS, buf, 1073 nbytes, addr); 1074 break; 1075 1076 case (uintptr_t)MDB_TGT_AS_VIRT_S: 1077 cnt = vmm_vwrite(bd->bd_vmm, bd->bd_curcpu, VMM_DESC_SS, buf, 1078 nbytes, addr); 1079 break; 1080 1081 case (uintptr_t)MDB_TGT_AS_PHYS: 1082 cnt = vmm_pwrite(bd->bd_vmm, buf, nbytes, addr); 1083 break; 1084 1085 case (uintptr_t)MDB_TGT_AS_FILE: 1086 case (uintptr_t)MDB_TGT_AS_IO: 1087 return (set_errno(EMDB_TGTNOTSUP)); 1088 } 1089 1090 if (errno == EFAULT) 1091 return (set_errno(EMDB_NOMAP)); 1092 1093 return (cnt); 1094 } 1095 1096 /* 1097 * t_vread: read from virtual memory 1098 */ 1099 /*ARGSUSED*/ 1100 static ssize_t 1101 bhyve_vread(mdb_tgt_t *tgt, void *buf, size_t nbytes, uintptr_t addr) 1102 { 1103 return (bhyve_aread(tgt, MDB_TGT_AS_VIRT, buf, nbytes, addr)); 1104 } 1105 1106 /* 1107 * t_vwrite: write to virtual memory 1108 */ 1109 /*ARGSUSED*/ 1110 static ssize_t 1111 bhyve_vwrite(mdb_tgt_t *tgt, const void *buf, size_t nbytes, uintptr_t addr) 1112 { 1113 return (bhyve_awrite(tgt, MDB_TGT_AS_VIRT, buf, nbytes, addr)); 1114 } 1115 1116 /* 1117 * t_pread: read from physical memory 1118 */ 1119 /*ARGSUSED*/ 1120 static ssize_t 1121 bhyve_pread(mdb_tgt_t *tgt, void *buf, size_t nbytes, physaddr_t addr) 1122 { 1123 return (bhyve_aread(tgt, MDB_TGT_AS_PHYS, buf, nbytes, addr)); 1124 } 1125 1126 /* 1127 * t_pwrite: write to physical memory 1128 */ 1129 /*ARGSUSED*/ 1130 static ssize_t 1131 bhyve_pwrite(mdb_tgt_t *tgt, const void *buf, size_t nbytes, physaddr_t addr) 1132 { 1133 return (bhyve_awrite(tgt, MDB_TGT_AS_PHYS, buf, nbytes, addr)); 1134 } 1135 1136 /* 1137 * t_fread: read from core/object file 1138 */ 1139 /*ARGSUSED*/ 1140 static ssize_t 1141 bhyve_fread(mdb_tgt_t *tgt, void *buf, size_t nbytes, uintptr_t addr) 1142 { 1143 return (bhyve_aread(tgt, MDB_TGT_AS_FILE, buf, nbytes, addr)); 1144 } 1145 1146 /* 1147 * t_fwrite: write to core/object file 1148 */ 1149 /*ARGSUSED*/ 1150 static ssize_t 1151 bhyve_fwrite(mdb_tgt_t *tgt, const void *buf, size_t nbytes, uintptr_t addr) 1152 { 1153 return (bhyve_awrite(tgt, MDB_TGT_AS_FILE, buf, nbytes, addr)); 1154 } 1155 1156 /* 1157 * t_ioread: read from I/O space 1158 */ 1159 /*ARGSUSED*/ 1160 static ssize_t 1161 bhyve_ioread(mdb_tgt_t *tgt, void *buf, size_t nbytes, uintptr_t addr) 1162 { 1163 return (bhyve_aread(tgt, MDB_TGT_AS_IO, buf, nbytes, addr)); 1164 } 1165 1166 /* 1167 * t_iowrite: write to I/O space 1168 */ 1169 /*ARGSUSED*/ 1170 static ssize_t 1171 bhyve_iowrite(mdb_tgt_t *tgt, const void *buf, size_t nbytes, uintptr_t addr) 1172 { 1173 return (bhyve_awrite(tgt, MDB_TGT_AS_IO, buf, nbytes, addr)); 1174 } 1175 1176 /* 1177 * t_vtop: translate virtual to physical address 1178 */ 1179 static int 1180 bhyve_vtop(mdb_tgt_t *tgt, mdb_tgt_as_t as, uintptr_t va, physaddr_t *pa) 1181 { 1182 bhyve_data_t *bd = tgt->t_data; 1183 int seg; 1184 1185 switch ((uintptr_t)as) { 1186 case (uintptr_t)MDB_TGT_AS_VIRT: 1187 seg = bd->bd_defseg; 1188 break; 1189 1190 case (uintptr_t)MDB_TGT_AS_VIRT_I: 1191 seg = VMM_DESC_CS; 1192 break; 1193 1194 case (uintptr_t)MDB_TGT_AS_VIRT_S: 1195 seg = VMM_DESC_SS; 1196 break; 1197 1198 default: 1199 return (set_errno(EINVAL)); 1200 } 1201 1202 if (vmm_vtop(bd->bd_vmm, bd->bd_curcpu, seg, va, pa) != 0) { 1203 if (errno == EFAULT) 1204 return (set_errno(EMDB_NOMAP)); 1205 else 1206 return (-1); 1207 } 1208 1209 return (0); 1210 } 1211 1212 /* 1213 * t_status: get target status 1214 */ 1215 static int 1216 bhyve_status(mdb_tgt_t *tgt, mdb_tgt_status_t *tsp) 1217 { 1218 bhyve_data_t *bd = tgt->t_data; 1219 mdb_tgt_reg_t rip; 1220 vmm_desc_t cs; 1221 int ret; 1222 1223 bzero(tsp, sizeof (mdb_tgt_status_t)); 1224 1225 ret = vmm_getreg(bd->bd_vmm, bd->bd_curcpu, KREG_RIP, &rip); 1226 if (ret != 0) { 1227 tsp->st_state = MDB_TGT_UNDEAD; 1228 } else { 1229 tsp->st_state = MDB_TGT_STOPPED; 1230 tsp->st_pc = rip; 1231 } 1232 1233 switch (vmm_vcpu_isa(bd->bd_vmm, bd->bd_curcpu)) { 1234 case VMM_ISA_16: 1235 (void) mdb_dis_select("ia16"); 1236 break; 1237 case VMM_ISA_32: 1238 (void) mdb_dis_select("ia32"); 1239 break; 1240 case VMM_ISA_64: 1241 (void) mdb_dis_select("amd64"); 1242 break; 1243 default: 1244 break; 1245 } 1246 1247 return (0); 1248 } 1249 1250 static void 1251 bhyve_sighdl(int sig, siginfo_t *sip, ucontext_t *ucp, mdb_tgt_t *tgt) 1252 { 1253 mdb_tgt_status_t *tsp = &tgt->t_status; 1254 bhyve_data_t *bd = tgt->t_data; 1255 1256 switch (sig) { 1257 case SIGINT: 1258 /* 1259 * vmm_stop() may fail if the VM was destroyed while we were 1260 * waiting. This will be handled by mdb_tgt_status(). 1261 */ 1262 (void) vmm_stop(bd->bd_vmm); 1263 (void) mdb_tgt_status(tgt, tsp); 1264 break; 1265 } 1266 } 1267 1268 /* 1269 * t_step: single-step target 1270 */ 1271 static int 1272 bhyve_step(mdb_tgt_t *tgt, mdb_tgt_status_t *tsp) 1273 { 1274 bhyve_data_t *bd = tgt->t_data; 1275 int ret; 1276 1277 ret = vmm_step(bd->bd_vmm, bd->bd_curcpu); 1278 (void) mdb_tgt_status(tgt, tsp); 1279 1280 return (ret); 1281 } 1282 1283 /* 1284 * t_cont: continue target execution 1285 * 1286 * Catch SIGINT so that the target can be stopped with Ctrl-C. 1287 */ 1288 static int 1289 bhyve_cont(mdb_tgt_t *tgt, mdb_tgt_status_t *tsp) 1290 { 1291 bhyve_data_t *bd = tgt->t_data; 1292 mdb_signal_f *intf; 1293 void *intd; 1294 int ret; 1295 1296 intf = mdb_signal_gethandler(SIGINT, &intd); 1297 (void) mdb_signal_sethandler(SIGINT, (mdb_signal_f *)bhyve_sighdl, tgt); 1298 1299 if (ret = vmm_cont(bd->bd_vmm) != 0) { 1300 mdb_warn("failed to continue target execution: %d", ret); 1301 return (set_errno(EMDB_TGT)); 1302 } 1303 1304 tsp->st_state = MDB_TGT_RUNNING; 1305 (void) pause(); 1306 1307 (void) mdb_signal_sethandler(SIGINT, intf, intd); 1308 (void) mdb_tgt_status(tgt, tsp); 1309 1310 return (ret); 1311 } 1312 1313 static int 1314 bhyve_lookup_reg(mdb_tgt_t *tgt, const char *rname) 1315 { 1316 bhyve_data_t *bd = tgt->t_data; 1317 const mdb_tgt_regdesc_t *rd; 1318 1319 for (rd = bhyve_kregs; rd->rd_name != NULL; rd++) 1320 if (strcmp(rd->rd_name, rname) == 0) 1321 return (rd->rd_num); 1322 1323 return (-1); 1324 } 1325 1326 /* 1327 * t_getareg: get the value of a single register 1328 */ 1329 static int 1330 bhyve_getareg(mdb_tgt_t *tgt, mdb_tgt_tid_t tid, const char *rname, 1331 mdb_tgt_reg_t *rp) 1332 { 1333 bhyve_data_t *bd = tgt->t_data; 1334 int reg = bhyve_lookup_reg(tgt, rname); 1335 int ret; 1336 1337 if (reg == -1) 1338 return (set_errno(EMDB_BADREG)); 1339 1340 ret = vmm_getreg(bd->bd_vmm, bd->bd_curcpu, reg, rp); 1341 if (ret == -1) 1342 return (set_errno(EMDB_BADREG)); 1343 1344 return (0); 1345 } 1346 1347 /* 1348 * t_putareg: set the value of a single register 1349 */ 1350 static int 1351 bhyve_putareg(mdb_tgt_t *tgt, mdb_tgt_tid_t tid, const char *rname, 1352 mdb_tgt_reg_t r) 1353 { 1354 bhyve_data_t *bd = tgt->t_data; 1355 int reg = bhyve_lookup_reg(tgt, rname); 1356 int ret; 1357 1358 if ((tgt->t_flags & MDB_TGT_F_RDWR) == 0) 1359 return (set_errno(EMDB_TGTRDONLY)); 1360 1361 if (reg == -1) 1362 return (set_errno(EMDB_BADREG)); 1363 1364 ret = vmm_setreg(bd->bd_vmm, bd->bd_curcpu, reg, r); 1365 if (ret == -1) 1366 return (set_errno(EMDB_BADREG)); 1367 1368 return (0); 1369 } 1370 1371 static const mdb_tgt_ops_t bhyve_ops = { 1372 .t_setflags = bhyve_setflags, 1373 .t_setcontext = (int (*)()) mdb_tgt_notsup, 1374 .t_activate = bhyve_activate, 1375 .t_deactivate = bhyve_deactivate, 1376 .t_periodic = (void (*)()) mdb_tgt_nop, 1377 .t_destroy = bhyve_destroy, 1378 .t_name = bhyve_name, 1379 .t_isa = bhyve_isa, 1380 .t_platform = (const char *(*)()) mdb_conf_platform, 1381 .t_uname = (int (*)()) mdb_tgt_notsup, 1382 .t_dmodel = bhyve_dmodel, 1383 .t_aread = bhyve_aread, 1384 .t_awrite = bhyve_awrite, 1385 .t_vread = bhyve_vread, 1386 .t_vwrite = bhyve_vwrite, 1387 .t_pread = bhyve_pread, 1388 .t_pwrite = bhyve_pwrite, 1389 .t_fread = bhyve_fread, 1390 .t_fwrite = bhyve_fwrite, 1391 .t_ioread = bhyve_ioread, 1392 .t_iowrite = bhyve_iowrite, 1393 .t_vtop = bhyve_vtop, 1394 .t_lookup_by_name = (int (*)()) mdb_tgt_notsup, 1395 .t_lookup_by_addr = (int (*)()) mdb_tgt_notsup, 1396 .t_symbol_iter = (int (*)()) mdb_tgt_notsup, 1397 .t_mapping_iter = (int (*)()) mdb_tgt_notsup, 1398 .t_object_iter = (int (*)()) mdb_tgt_notsup, 1399 .t_addr_to_map = (const mdb_map_t *(*)()) mdb_tgt_null, 1400 .t_name_to_map = (const mdb_map_t *(*)()) mdb_tgt_null, 1401 .t_addr_to_ctf = (struct ctf_file *(*)()) mdb_tgt_null, 1402 .t_name_to_ctf = (struct ctf_file *(*)()) mdb_tgt_null, 1403 .t_status = bhyve_status, 1404 .t_run = (int (*)()) mdb_tgt_notsup, 1405 .t_step = bhyve_step, 1406 .t_step_out = (int (*)()) mdb_tgt_notsup, 1407 .t_next = (int (*)()) mdb_tgt_notsup, 1408 .t_cont = bhyve_cont, 1409 .t_signal = (int (*)()) mdb_tgt_notsup, 1410 .t_add_vbrkpt = (int (*)()) mdb_tgt_null, 1411 .t_add_sbrkpt = (int (*)()) mdb_tgt_null, 1412 .t_add_pwapt = (int (*)()) mdb_tgt_null, 1413 .t_add_vwapt = (int (*)()) mdb_tgt_null, 1414 .t_add_iowapt = (int (*)()) mdb_tgt_null, 1415 .t_add_sysenter = (int (*)()) mdb_tgt_null, 1416 .t_add_sysexit = (int (*)()) mdb_tgt_null, 1417 .t_add_signal = (int (*)()) mdb_tgt_null, 1418 .t_add_fault = (int (*)()) mdb_tgt_null, 1419 .t_getareg = bhyve_getareg, 1420 .t_putareg = bhyve_putareg, 1421 .t_stack_iter = (int (*)()) mdb_tgt_notsup, 1422 .t_auxv = (int (*)()) mdb_tgt_notsup 1423 }; 1424 1425 int 1426 mdb_bhyve_tgt_create(mdb_tgt_t *tgt, int argc, const char *argv[]) 1427 { 1428 bhyve_data_t *bd; 1429 vmm_t *vmm = NULL; 1430 boolean_t writable = (tgt->t_flags & MDB_TGT_F_RDWR) != 0; 1431 1432 if (argc != 1) 1433 return (set_errno(EINVAL)); 1434 1435 vmm = vmm_open_vm(argv[0]); 1436 if (vmm == NULL) { 1437 mdb_warn("failed to open %s", argv[0]); 1438 return (set_errno(EMDB_TGT)); 1439 } 1440 1441 if (vmm_map(vmm, writable) != 0) { 1442 mdb_warn("failed to map %s", argv[0]); 1443 vmm_close_vm(vmm); 1444 return (set_errno(EMDB_TGT)); 1445 } 1446 1447 bd = mdb_zalloc(sizeof (bhyve_data_t) + strlen(argv[0]) + 1, UM_SLEEP); 1448 (void) strcpy(bd->bd_name, argv[0]); 1449 bd->bd_vmm = vmm; 1450 bd->bd_curcpu = 0; 1451 bd->bd_defseg = VMM_DESC_DS; 1452 1453 tgt->t_ops = &bhyve_ops; 1454 tgt->t_data = bd; 1455 tgt->t_flags |= MDB_TGT_F_ASIO; 1456 1457 (void) mdb_nv_insert(&mdb.m_nv, "cpuid", &bhyve_cpuid_disc, 0, 1458 MDB_NV_PERSIST | MDB_NV_RDONLY); 1459 1460 return (0); 1461 } 1462