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 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 /* 27 * Copyright (c) 2018, Joyent, Inc. 28 * Copyright 2019 Doma Gergő Mihály <doma.gergo.mihaly@gmail.com> 29 * Copyright 2023 Oxide Computer Company 30 */ 31 32 /* 33 * User Process Target Intel 64-bit component 34 * 35 * This file provides the ISA-dependent portion of the user process target. 36 * For more details on the implementation refer to mdb_proc.c. 37 */ 38 39 #include <mdb/mdb_proc.h> 40 #include <mdb/mdb_kreg.h> 41 #include <mdb/mdb_err.h> 42 #include <mdb/mdb_isautil.h> 43 #include <mdb/mdb_amd64util.h> 44 #include <mdb/proc_x86util.h> 45 #include <mdb/mdb.h> 46 47 #include <sys/ucontext.h> 48 #include <sys/frame.h> 49 #include <libproc.h> 50 #include <sys/fp.h> 51 #include <ieeefp.h> 52 #include <sys/sysmacros.h> 53 54 #include <stddef.h> 55 56 const mdb_tgt_regdesc_t pt_regdesc[] = { 57 { "r15", REG_R15, MDB_TGT_R_EXPORT }, 58 { "r15d", REG_R15, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 59 { "r15w", REG_R15, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 60 { "r15l", REG_R15, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 61 { "r14", REG_R14, MDB_TGT_R_EXPORT }, 62 { "r14d", REG_R14, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 63 { "r14w", REG_R14, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 64 { "r14l", REG_R14, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 65 { "r13", REG_R13, MDB_TGT_R_EXPORT }, 66 { "r13d", REG_R13, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 67 { "r13w", REG_R13, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 68 { "r13l", REG_R13, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 69 { "r12", REG_R12, MDB_TGT_R_EXPORT }, 70 { "r12d", REG_R12, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 71 { "r12w", REG_R12, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 72 { "r12l", REG_R12, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 73 { "r11", REG_R11, MDB_TGT_R_EXPORT }, 74 { "r11d", REG_R11, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 75 { "r11w", REG_R11, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 76 { "r11l", REG_R11, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 77 { "r10", REG_R10, MDB_TGT_R_EXPORT }, 78 { "r10d", REG_R10, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 79 { "r10w", REG_R10, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 80 { "r10l", REG_R10, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 81 { "r9", REG_R9, MDB_TGT_R_EXPORT }, 82 { "r9d", REG_R9, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 83 { "r9w", REG_R9, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 84 { "r9l", REG_R9, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 85 { "r8", REG_R8, MDB_TGT_R_EXPORT }, 86 { "r8d", REG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 87 { "r8w", REG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 88 { "r8l", REG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 89 { "rdi", REG_RDI, MDB_TGT_R_EXPORT }, 90 { "edi", REG_RDI, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 91 { "di", REG_RDI, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 92 { "dil", REG_RDI, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 93 { "rsi", REG_RSI, MDB_TGT_R_EXPORT }, 94 { "esi", REG_RSI, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 95 { "si", REG_RSI, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 96 { "sil", REG_RSI, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 97 { "rbp", REG_RBP, MDB_TGT_R_EXPORT }, 98 { "ebp", REG_RBP, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 99 { "bp", REG_RBP, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 100 { "bpl", REG_RBP, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 101 { "rbx", REG_RBX, MDB_TGT_R_EXPORT }, 102 { "ebx", REG_RBX, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 103 { "bx", REG_RBX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 104 { "bh", REG_RBX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H }, 105 { "bl", REG_RBX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 106 { "rdx", REG_RDX, MDB_TGT_R_EXPORT }, 107 { "edx", REG_RDX, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 108 { "dx", REG_RDX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 109 { "dh", REG_RDX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H }, 110 { "dl", REG_RDX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 111 { "rcx", REG_RCX, MDB_TGT_R_EXPORT }, 112 { "ecx", REG_RCX, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 113 { "cx", REG_RCX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 114 { "ch", REG_RCX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H }, 115 { "cl", REG_RCX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 116 { "rax", REG_RAX, MDB_TGT_R_EXPORT }, 117 { "eax", REG_RAX, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 118 { "ax", REG_RAX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 119 { "ah", REG_RAX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H }, 120 { "al", REG_RAX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 121 { "trapno", REG_TRAPNO, MDB_TGT_R_EXPORT }, 122 { "err", REG_ERR, MDB_TGT_R_EXPORT }, 123 { "rip", REG_RIP, MDB_TGT_R_EXPORT }, 124 { "cs", REG_CS, MDB_TGT_R_EXPORT }, 125 { "rflags", REG_RFL, MDB_TGT_R_EXPORT }, 126 { "eflags", REG_RFL, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 127 { "rsp", REG_RSP, MDB_TGT_R_EXPORT }, 128 { "esp", REG_RSP, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 129 { "sp", REG_RSP, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 130 { "spl", REG_RSP, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 131 { "ss", REG_SS, MDB_TGT_R_EXPORT }, 132 { "fs", REG_FS, MDB_TGT_R_EXPORT }, 133 { "gs", REG_GS, MDB_TGT_R_EXPORT }, 134 { "es", REG_ES, MDB_TGT_R_EXPORT }, 135 { "ds", REG_DS, MDB_TGT_R_EXPORT }, 136 { "fsbase", REG_FSBASE, MDB_TGT_R_EXPORT }, 137 { "gsbase", REG_GSBASE, MDB_TGT_R_EXPORT }, 138 { NULL, 0, 0 } 139 }; 140 141 /* 142 * We cannot rely on pr_instr, because if we hit a breakpoint or the user has 143 * artifically modified memory, it will no longer be correct. 144 */ 145 static uint8_t 146 pt_read_instr(mdb_tgt_t *t) 147 { 148 const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp; 149 uint8_t ret = 0; 150 151 (void) mdb_tgt_aread(t, MDB_TGT_AS_VIRT_I, &ret, sizeof (ret), 152 psp->pr_reg[REG_RIP]); 153 154 return (ret); 155 } 156 157 /*ARGSUSED*/ 158 int 159 pt_regs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 160 { 161 mdb_tgt_t *t = mdb.m_target; 162 mdb_tgt_tid_t tid; 163 prgregset_t grs; 164 prgreg_t rflags; 165 boolean_t from_ucontext = B_FALSE; 166 167 if (mdb_getopts(argc, argv, 168 'u', MDB_OPT_SETBITS, B_TRUE, &from_ucontext, NULL) != argc) { 169 return (DCMD_USAGE); 170 } 171 172 if (from_ucontext) { 173 int off; 174 int o0, o1; 175 176 if (!(flags & DCMD_ADDRSPEC)) { 177 mdb_warn("-u requires a ucontext_t address\n"); 178 return (DCMD_ERR); 179 } 180 181 o0 = mdb_ctf_offsetof_by_name("ucontext_t", "uc_mcontext"); 182 o1 = mdb_ctf_offsetof_by_name("mcontext_t", "gregs"); 183 if (o0 == -1 || o1 == -1) { 184 off = offsetof(ucontext_t, uc_mcontext) + 185 offsetof(mcontext_t, gregs); 186 } else { 187 off = o0 + o1; 188 } 189 190 if (mdb_vread(&grs, sizeof (grs), addr + off) != sizeof (grs)) { 191 mdb_warn("failed to read from ucontext_t %p", addr); 192 return (DCMD_ERR); 193 } 194 goto print_regs; 195 } 196 197 if (t->t_pshandle == NULL || Pstate(t->t_pshandle) == PS_UNDEAD) { 198 mdb_warn("no process active\n"); 199 return (DCMD_ERR); 200 } 201 202 if (Pstate(t->t_pshandle) == PS_LOST) { 203 mdb_warn("debugger has lost control of process\n"); 204 return (DCMD_ERR); 205 } 206 207 if (flags & DCMD_ADDRSPEC) 208 tid = (mdb_tgt_tid_t)addr; 209 else 210 tid = PTL_TID(t); 211 212 if (PTL_GETREGS(t, tid, grs) != 0) { 213 mdb_warn("failed to get current register set"); 214 return (DCMD_ERR); 215 } 216 217 print_regs: 218 rflags = grs[REG_RFL]; 219 220 mdb_printf("%%rax = 0x%0?p\t%%r8 = 0x%0?p\n", 221 grs[REG_RAX], grs[REG_R8]); 222 mdb_printf("%%rbx = 0x%0?p\t%%r9 = 0x%0?p\n", 223 grs[REG_RBX], grs[REG_R9]); 224 mdb_printf("%%rcx = 0x%0?p\t%%r10 = 0x%0?p\n", 225 grs[REG_RCX], grs[REG_R10]); 226 mdb_printf("%%rdx = 0x%0?p\t%%r11 = 0x%0?p\n", 227 grs[REG_RDX], grs[REG_R11]); 228 mdb_printf("%%rsi = 0x%0?p\t%%r12 = 0x%0?p\n", 229 grs[REG_RSI], grs[REG_R12]); 230 mdb_printf("%%rdi = 0x%0?p\t%%r13 = 0x%0?p\n", 231 grs[REG_RDI], grs[REG_R13]); 232 mdb_printf(" %?s\t%%r14 = 0x%0?p\n", 233 "", grs[REG_R14]); 234 mdb_printf(" %?s\t%%r15 = 0x%0?p\n", 235 "", grs[REG_R15]); 236 237 mdb_printf("\n"); 238 239 mdb_printf("%%cs = 0x%04x\t%%fs = 0x%04x\t%%gs = 0x%04x\n", 240 grs[REG_CS], grs[REG_FS], grs[REG_GS]); 241 mdb_printf("%%ds = 0x%04x\t%%es = 0x%04x\t%%ss = 0x%04x\n", 242 grs[REG_DS], grs[REG_ES], grs[REG_SS]); 243 244 mdb_printf("\n"); 245 246 mdb_printf("%%rip = 0x%0?p %A\n", grs[REG_RIP], grs[REG_RIP]); 247 mdb_printf("%%rbp = 0x%0?p\n", grs[REG_RBP], grs[REG_RBP]); 248 mdb_printf("%%rsp = 0x%0?p\n", grs[REG_RSP], grs[REG_RSP]); 249 250 mdb_printf("\n"); 251 252 mdb_printf("%%rflags = 0x%08x\n", rflags); 253 254 mdb_printf(" id=%u vip=%u vif=%u ac=%u vm=%u rf=%u nt=%u iopl=0x%x\n", 255 (rflags & KREG_EFLAGS_ID_MASK) >> KREG_EFLAGS_ID_SHIFT, 256 (rflags & KREG_EFLAGS_VIP_MASK) >> KREG_EFLAGS_VIP_SHIFT, 257 (rflags & KREG_EFLAGS_VIF_MASK) >> KREG_EFLAGS_VIF_SHIFT, 258 (rflags & KREG_EFLAGS_AC_MASK) >> KREG_EFLAGS_AC_SHIFT, 259 (rflags & KREG_EFLAGS_VM_MASK) >> KREG_EFLAGS_VM_SHIFT, 260 (rflags & KREG_EFLAGS_RF_MASK) >> KREG_EFLAGS_RF_SHIFT, 261 (rflags & KREG_EFLAGS_NT_MASK) >> KREG_EFLAGS_NT_SHIFT, 262 (rflags & KREG_EFLAGS_IOPL_MASK) >> KREG_EFLAGS_IOPL_SHIFT); 263 264 mdb_printf(" status=<%s,%s,%s,%s,%s,%s,%s,%s,%s>\n", 265 (rflags & KREG_EFLAGS_OF_MASK) ? "OF" : "of", 266 (rflags & KREG_EFLAGS_DF_MASK) ? "DF" : "df", 267 (rflags & KREG_EFLAGS_IF_MASK) ? "IF" : "if", 268 (rflags & KREG_EFLAGS_TF_MASK) ? "TF" : "tf", 269 (rflags & KREG_EFLAGS_SF_MASK) ? "SF" : "sf", 270 (rflags & KREG_EFLAGS_ZF_MASK) ? "ZF" : "zf", 271 (rflags & KREG_EFLAGS_AF_MASK) ? "AF" : "af", 272 (rflags & KREG_EFLAGS_PF_MASK) ? "PF" : "pf", 273 (rflags & KREG_EFLAGS_CF_MASK) ? "CF" : "cf"); 274 275 mdb_printf("\n"); 276 277 mdb_printf("%%gsbase = 0x%0?p\n", grs[REG_GSBASE]); 278 mdb_printf("%%fsbase = 0x%0?p\n", grs[REG_FSBASE]); 279 mdb_printf("%%trapno = 0x%x\n", grs[REG_TRAPNO]); 280 mdb_printf(" %%err = 0x%x\n", grs[REG_ERR]); 281 282 return (set_errno(ENOTSUP)); 283 } 284 285 int 286 pt_fpregs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 287 { 288 int ret; 289 prfpregset_t fprs; 290 struct _fpchip_state fps; 291 char buf[256]; 292 uint_t top; 293 size_t i; 294 295 /* 296 * Union for overlaying _fpreg structure on to quad-precision 297 * floating-point value (long double). 298 */ 299 union { 300 struct _fpreg reg; 301 long double ld; 302 } fpru; 303 304 /* 305 * We use common code between 32-bit and 64-bit x86 to capture and print 306 * the extended vector state. The remaining classic 387 state is 307 * finicky and different enough that it is left to be dealt with on its 308 * own. 309 */ 310 if ((ret = x86_pt_fpregs_common(addr, flags, argc, &fprs)) != DCMD_OK) 311 return (ret); 312 313 bcopy(&fprs.fp_reg_set.fpchip_state, &fps, sizeof (fps)); 314 mdb_printf("387 and FP Control State\n"); 315 316 fps.status &= 0xffff; /* saved status word is really 16 bits */ 317 318 mdb_printf("cw 0x%04x (%s)\n", fps.cw, 319 fpcw2str(fps.cw, buf, sizeof (buf))); 320 321 top = (fps.sw & FPS_TOP) >> 11; 322 mdb_printf("sw 0x%04x (TOP=0t%u) (%s)\n", fps.sw, 323 top, fpsw2str(fps.sw, buf, sizeof (buf))); 324 325 mdb_printf("xcp sw 0x%04x (%s)\n\n", fps.status, 326 fpsw2str(fps.status, buf, sizeof (buf))); 327 328 mdb_printf("fop 0x%x\n", fps.fop); 329 mdb_printf("rip 0x%x\n", fps.rip); 330 mdb_printf("rdp 0x%x\n\n", fps.rdp); 331 332 for (i = 0; i < ARRAY_SIZE(fps.st); i++) { 333 /* 334 * Recall that we need to use the current TOP-of-stack value to 335 * associate the _st[] index back to a physical register number, 336 * since tag word indices are physical register numbers. Then 337 * to get the tag value, we shift over two bits for each tag 338 * index, and then grab the bottom two bits. 339 */ 340 uint_t tag_index = (i + top) & 7; 341 uint_t tag_fctw = (fps.fctw >> tag_index) & 1; 342 uint_t tag_value; 343 uint_t exp; 344 345 /* 346 * AMD64 stores the tag in a compressed form. It is 347 * necessary to extract the original 2-bit tag value. 348 * See AMD64 Architecture Programmer's Manual Volume 2: 349 * System Programming, Chapter 11. 350 */ 351 352 fpru.ld = fps.st[i].__fpr_pad._q; 353 exp = fpru.reg.exponent & 0x7fff; 354 355 if (tag_fctw == 0) { 356 tag_value = 3; /* empty */ 357 } else if (exp == 0) { 358 if (fpru.reg.significand[0] == 0 && 359 fpru.reg.significand[1] == 0 && 360 fpru.reg.significand[2] == 0 && 361 fpru.reg.significand[3] == 0) 362 tag_value = 1; /* zero */ 363 else 364 tag_value = 2; /* special: denormal */ 365 } else if (exp == 0x7fff) { 366 tag_value = 2; /* special: infinity or NaN */ 367 } else if (fpru.reg.significand[3] & 0x8000) { 368 tag_value = 0; /* valid */ 369 } else { 370 tag_value = 2; /* special: unnormal */ 371 } 372 373 mdb_printf("%%st%d 0x%04x.%04x%04x%04x%04x = %lg %s\n", 374 i, fpru.reg.exponent, 375 fpru.reg.significand[3], fpru.reg.significand[2], 376 fpru.reg.significand[1], fpru.reg.significand[0], 377 fpru.ld, fptag2str(tag_value)); 378 } 379 380 x86_pt_fpregs_sse_ctl(fps.mxcsr, fps.xstatus, buf, sizeof (buf)); 381 382 return (DCMD_OK); 383 } 384 385 /*ARGSUSED*/ 386 int 387 pt_getfpreg(mdb_tgt_t *t, mdb_tgt_tid_t tid, ushort_t rd_num, 388 ushort_t rd_flags, mdb_tgt_reg_t *rp) 389 { 390 return (set_errno(ENOTSUP)); 391 } 392 393 /*ARGSUSED*/ 394 int 395 pt_putfpreg(mdb_tgt_t *t, mdb_tgt_tid_t tid, ushort_t rd_num, 396 ushort_t rd_flags, mdb_tgt_reg_t rval) 397 { 398 return (set_errno(ENOTSUP)); 399 } 400 401 /*ARGSUSED*/ 402 void 403 pt_addfpregs(mdb_tgt_t *t) 404 { 405 /* not implemented */ 406 } 407 408 /*ARGSUSED*/ 409 int 410 pt_frameregs(void *arglim, uintptr_t pc, uint_t argc, const long *argv, 411 const mdb_tgt_gregset_t *gregs, boolean_t pc_faked) 412 { 413 return (set_errno(ENOTSUP)); 414 } 415 416 /*ARGSUSED*/ 417 const char * 418 pt_disasm(const GElf_Ehdr *ehp) 419 { 420 return ("amd64"); 421 } 422 423 /* 424 * Determine the return address for the current frame. 425 */ 426 int 427 pt_step_out(mdb_tgt_t *t, uintptr_t *p) 428 { 429 const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp; 430 431 if (Pstate(t->t_pshandle) != PS_STOP) 432 return (set_errno(EMDB_TGTBUSY)); 433 434 return (mdb_amd64_step_out(t, p, psp->pr_reg[REG_RIP], 435 psp->pr_reg[REG_RBP], psp->pr_reg[REG_RSP], psp->pr_instr)); 436 } 437 438 /* 439 * Return the address of the next instruction following a call, or return -1 440 * and set errno to EAGAIN if the target should just single-step. 441 */ 442 int 443 pt_next(mdb_tgt_t *t, uintptr_t *p) 444 { 445 const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp; 446 447 if (Pstate(t->t_pshandle) != PS_STOP) 448 return (set_errno(EMDB_TGTBUSY)); 449 450 return (mdb_amd64_next(t, p, psp->pr_reg[REG_RIP], pt_read_instr(t))); 451 } 452