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