dtrace_isa.c revision 302408
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 * $FreeBSD: stable/11/sys/cddl/dev/dtrace/mips/dtrace_isa.c 295882 2016-02-22 09:08:04Z skra $ 23 */ 24/* 25 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 26 * Use is subject to license terms. 27 */ 28#include <sys/cdefs.h> 29 30#include <sys/param.h> 31#include <sys/systm.h> 32#include <sys/kernel.h> 33#include <sys/stack.h> 34#include <sys/pcpu.h> 35 36#include <machine/frame.h> 37#include <machine/md_var.h> 38#include <machine/reg.h> 39 40#include <vm/vm.h> 41#include <vm/vm_param.h> 42#include <vm/pmap.h> 43 44#include <machine/db_machdep.h> 45#include <machine/md_var.h> 46#include <machine/mips_opcode.h> 47#include <ddb/db_sym.h> 48#include <ddb/ddb.h> 49#include <sys/kdb.h> 50 51#include "regset.h" 52 53#ifdef __mips_n64 54#define MIPS_IS_VALID_KERNELADDR(reg) ((((reg) & 3) == 0) && \ 55 ((vm_offset_t)(reg) >= MIPS_XKPHYS_START)) 56#else 57#define MIPS_IS_VALID_KERNELADDR(reg) ((((reg) & 3) == 0) && \ 58 ((vm_offset_t)(reg) >= MIPS_KSEG0_START)) 59#endif 60 61 62 63/* 64 * Wee need some reasonable default to prevent backtrace code 65 * from wandering too far 66 */ 67#define MAX_FUNCTION_SIZE 0x10000 68#define MAX_PROLOGUE_SIZE 0x100 69 70uint8_t dtrace_fuword8_nocheck(void *); 71uint16_t dtrace_fuword16_nocheck(void *); 72uint32_t dtrace_fuword32_nocheck(void *); 73uint64_t dtrace_fuword64_nocheck(void *); 74 75static int dtrace_next_frame(register_t *pc, register_t *sp, register_t *args, int *valid_args); 76static int dtrace_next_uframe(register_t *pc, register_t *sp, register_t *ra); 77 78void 79dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, 80 uint32_t *intrpc) 81{ 82 int depth = 0; 83 vm_offset_t callpc; 84 pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller; 85 register_t sp, ra, pc; 86 87 if (intrpc != 0) 88 pcstack[depth++] = (pc_t) intrpc; 89 90 aframes++; 91 92 sp = (register_t)(intptr_t)__builtin_frame_address(0); 93 ra = (register_t)(intptr_t)__builtin_return_address(0); 94 95 __asm __volatile( 96 "jal 99f\n" 97 "nop\n" 98 "99:\n" 99 "move %0, $31\n" /* get ra */ 100 "move $31, %1\n" /* restore ra */ 101 : "=r" (pc) 102 : "r" (ra)); 103 104 while (depth < pcstack_limit) { 105 106 callpc = pc; 107 108 if (aframes > 0) { 109 aframes--; 110 if ((aframes == 0) && (caller != 0)) { 111 pcstack[depth++] = caller; 112 } 113 } 114 else { 115 pcstack[depth++] = callpc; 116 } 117 118 if (dtrace_next_frame(&pc, &sp, NULL, NULL) < 0) 119 break; 120 } 121 122 for (; depth < pcstack_limit; depth++) { 123 pcstack[depth] = 0; 124 } 125} 126 127void 128dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) 129{ 130 proc_t *p = curproc; 131 struct trapframe *tf; 132 register_t sp, ra, pc; 133 volatile uint16_t *flags = 134 (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 135 136 if (*flags & CPU_DTRACE_FAULT) 137 return; 138 139 if (pcstack_limit <= 0) 140 return; 141 142 /* 143 * If there's no user context we still need to zero the stack. 144 */ 145 if (p == NULL || (tf = curthread->td_frame) == NULL) 146 goto zero; 147 148 *pcstack++ = (uint64_t)p->p_pid; 149 pcstack_limit--; 150 151 if (pcstack_limit <= 0) 152 return; 153 154 pc = (uint64_t)tf->pc; 155 sp = (uint64_t)tf->sp; 156 ra = (uint64_t)tf->ra; 157 *pcstack++ = (uint64_t)tf->pc; 158 159 /* 160 * Unwind, and unwind, and unwind 161 */ 162 while (1) { 163 if (dtrace_next_uframe(&pc, &sp, &ra) < 0) 164 break; 165 166 *pcstack++ = pc; 167 pcstack_limit--; 168 169 if (pcstack_limit <= 0) 170 break; 171 } 172 173zero: 174 while (pcstack_limit-- > 0) 175 *pcstack++ = 0; 176} 177 178int 179dtrace_getustackdepth(void) 180{ 181 int n = 0; 182 proc_t *p = curproc; 183 struct trapframe *tf; 184 register_t sp, ra, pc; 185 volatile uint16_t *flags = 186 (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 187 188 if (*flags & CPU_DTRACE_FAULT) 189 return (0); 190 191 if (p == NULL || (tf = curthread->td_frame) == NULL) 192 return (0); 193 194 pc = (uint64_t)tf->pc; 195 sp = (uint64_t)tf->sp; 196 ra = (uint64_t)tf->ra; 197 n++; 198 199 /* 200 * Unwind, and unwind, and unwind 201 */ 202 while (1) { 203 if (dtrace_next_uframe(&pc, &sp, &ra) < 0) 204 break; 205 n++; 206 } 207 208 return (n); 209} 210 211void 212dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) 213{ 214 printf("IMPLEMENT ME: %s\n", __func__); 215} 216 217/*ARGSUSED*/ 218uint64_t 219dtrace_getarg(int arg, int aframes) 220{ 221 int i; 222 register_t sp, ra, pc; 223 /* XXX: Fix this ugly code */ 224 register_t args[8]; 225 int valid[8]; 226 227 sp = (register_t)(intptr_t)__builtin_frame_address(0); 228 ra = (register_t)(intptr_t)__builtin_return_address(0); 229 230 __asm __volatile( 231 "jal 99f\n" 232 "nop\n" 233 "99:\n" 234 "move %0, $31\n" /* get ra */ 235 "move $31, %1\n" /* restore ra */ 236 : "=r" (pc) 237 : "r" (ra)); 238 239 for (i = 0; i <= aframes + 1; i++) { 240 if (dtrace_next_frame(&pc, &sp, args, valid) < 0) { 241 printf("%s: stack ends at frame #%d\n", __func__, i); 242 return (0); 243 } 244 } 245 246 if (arg < 8) { 247 if (valid[arg]) 248 return (args[arg]); 249 else 250 printf("%s: request arg%d is not valid\n", __func__, arg); 251 } 252 253 return (0); 254} 255 256int 257dtrace_getstackdepth(int aframes) 258{ 259 register_t sp, ra, pc; 260 int depth = 0; 261 262 sp = (register_t)(intptr_t)__builtin_frame_address(0); 263 ra = (register_t)(intptr_t)__builtin_return_address(0); 264 265 __asm __volatile( 266 "jal 99f\n" 267 "nop\n" 268 "99:\n" 269 "move %0, $31\n" /* get ra */ 270 "move $31, %1\n" /* restore ra */ 271 : "=r" (pc) 272 : "r" (ra)); 273 274 for (;;) { 275 if (dtrace_next_frame(&pc, &sp, NULL, NULL) < 0) 276 break; 277 depth++; 278 } 279 280 if (depth < aframes) 281 return 0; 282 else 283 return depth - aframes; 284} 285 286ulong_t 287dtrace_getreg(struct trapframe *rp, uint_t reg) 288{ 289 290 return (0); 291} 292 293static int 294dtrace_next_frame(register_t *pc, register_t *sp, 295 register_t *args, int *valid_args) 296{ 297 InstFmt i; 298 /* 299 * Arrays for a0..a3 registers and flags if content 300 * of these registers is valid, e.g. obtained from the stack 301 */ 302 uintptr_t va; 303 unsigned instr, mask; 304 unsigned int frames = 0; 305 int more, stksize; 306 register_t ra = 0; 307 int arg, r; 308 vm_offset_t addr; 309 310 /* 311 * Invalidate arguments values 312 */ 313 if (valid_args) { 314 for (r = 0; r < 8; r++) 315 valid_args[r] = 0; 316 } 317 318 /* Jump here after a nonstandard (interrupt handler) frame */ 319 stksize = 0; 320 if (frames++ > 100) { 321 /* return breaks stackframe-size heuristics with gcc -O2 */ 322 goto error; /* XXX */ 323 } 324 325 /* check for bad SP: could foul up next frame */ 326 if (!MIPS_IS_VALID_KERNELADDR(*sp)) { 327 goto error; 328 } 329 330 /* check for bad PC */ 331 if (!MIPS_IS_VALID_KERNELADDR(*pc)) { 332 goto error; 333 } 334 335 /* 336 * Find the beginning of the current subroutine by scanning 337 * backwards from the current PC for the end of the previous 338 * subroutine. 339 */ 340 va = *pc - sizeof(int); 341 while (1) { 342 instr = kdbpeek((int *)va); 343 344 /* [d]addiu sp,sp,-X */ 345 if (((instr & 0xffff8000) == 0x27bd8000) 346 || ((instr & 0xffff8000) == 0x67bd8000)) 347 break; 348 349 /* jr ra */ 350 if (instr == 0x03e00008) { 351 /* skip over branch-delay slot instruction */ 352 va += 2 * sizeof(int); 353 break; 354 } 355 356 va -= sizeof(int); 357 } 358 359 /* skip over nulls which might separate .o files */ 360 while ((instr = kdbpeek((int *)va)) == 0) 361 va += sizeof(int); 362 363 /* scan forwards to find stack size and any saved registers */ 364 stksize = 0; 365 more = 3; 366 mask = 0; 367 for (; more; va += sizeof(int), 368 more = (more == 3) ? 3 : more - 1) { 369 /* stop if hit our current position */ 370 if (va >= *pc) 371 break; 372 instr = kdbpeek((int *)va); 373 i.word = instr; 374 switch (i.JType.op) { 375 case OP_SPECIAL: 376 switch (i.RType.func) { 377 case OP_JR: 378 case OP_JALR: 379 more = 2; /* stop after next instruction */ 380 break; 381 382 case OP_SYSCALL: 383 case OP_BREAK: 384 more = 1; /* stop now */ 385 }; 386 break; 387 388 case OP_BCOND: 389 case OP_J: 390 case OP_JAL: 391 case OP_BEQ: 392 case OP_BNE: 393 case OP_BLEZ: 394 case OP_BGTZ: 395 more = 2; /* stop after next instruction */ 396 break; 397 398 case OP_COP0: 399 case OP_COP1: 400 case OP_COP2: 401 case OP_COP3: 402 switch (i.RType.rs) { 403 case OP_BCx: 404 case OP_BCy: 405 more = 2; /* stop after next instruction */ 406 }; 407 break; 408 409 case OP_SW: 410 /* look for saved registers on the stack */ 411 if (i.IType.rs != 29) 412 break; 413 /* only restore the first one */ 414 if (mask & (1 << i.IType.rt)) 415 break; 416 mask |= (1 << i.IType.rt); 417 addr = (vm_offset_t)(*sp + (short)i.IType.imm); 418 switch (i.IType.rt) { 419 case 4:/* a0 */ 420 case 5:/* a1 */ 421 case 6:/* a2 */ 422 case 7:/* a3 */ 423#if defined(__mips_n64) || defined(__mips_n32) 424 case 8:/* a4 */ 425 case 9:/* a5 */ 426 case 10:/* a6 */ 427 case 11:/* a7 */ 428#endif 429 arg = i.IType.rt - 4; 430 if (args) 431 args[arg] = kdbpeek((int*)addr); 432 if (valid_args) 433 valid_args[arg] = 1; 434 break; 435 case 31: /* ra */ 436 ra = kdbpeek((int *)addr); 437 } 438 break; 439 440 case OP_SD: 441 /* look for saved registers on the stack */ 442 if (i.IType.rs != 29) 443 break; 444 /* only restore the first one */ 445 if (mask & (1 << i.IType.rt)) 446 break; 447 mask |= (1 << i.IType.rt); 448 addr = (vm_offset_t)(*sp + (short)i.IType.imm); 449 switch (i.IType.rt) { 450 case 4:/* a0 */ 451 case 5:/* a1 */ 452 case 6:/* a2 */ 453 case 7:/* a3 */ 454#if defined(__mips_n64) || defined(__mips_n32) 455 case 8:/* a4 */ 456 case 9:/* a5 */ 457 case 10:/* a6 */ 458 case 11:/* a7 */ 459#endif 460 arg = i.IType.rt - 4; 461 if (args) 462 args[arg] = kdbpeekd((int *)addr); 463 if (valid_args) 464 valid_args[arg] = 1; 465 break; 466 467 case 31: /* ra */ 468 ra = kdbpeekd((int *)addr); 469 } 470 break; 471 472 case OP_ADDI: 473 case OP_ADDIU: 474 case OP_DADDI: 475 case OP_DADDIU: 476 /* look for stack pointer adjustment */ 477 if (i.IType.rs != 29 || i.IType.rt != 29) 478 break; 479 stksize = -((short)i.IType.imm); 480 } 481 } 482 483 if (!MIPS_IS_VALID_KERNELADDR(ra)) 484 return (-1); 485 486 *pc = ra; 487 *sp += stksize; 488 489#if defined(__mips_o32) 490 /* 491 * For MIPS32 fill out arguments 5..8 from the stack 492 */ 493 for (arg = 4; arg < 8; arg++) { 494 addr = (vm_offset_t)(*sp + arg*sizeof(register_t)); 495 if (args) 496 args[arg] = kdbpeekd((int *)addr); 497 if (valid_args) 498 valid_args[arg] = 1; 499 } 500#endif 501 502 return (0); 503error: 504 return (-1); 505} 506 507static int 508dtrace_next_uframe(register_t *pc, register_t *sp, register_t *ra) 509{ 510 int offset, registers_on_stack; 511 uint32_t opcode, mask; 512 register_t function_start; 513 int stksize; 514 InstFmt i; 515 516 volatile uint16_t *flags = 517 (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 518 519 registers_on_stack = 0; 520 mask = 0; 521 function_start = 0; 522 offset = 0; 523 stksize = 0; 524 525 while (offset < MAX_FUNCTION_SIZE) { 526 opcode = dtrace_fuword32((void *)(vm_offset_t)(*pc - offset)); 527 528 if (*flags & CPU_DTRACE_FAULT) 529 goto fault; 530 531 /* [d]addiu sp, sp, -X*/ 532 if (((opcode & 0xffff8000) == 0x27bd8000) 533 || ((opcode & 0xffff8000) == 0x67bd8000)) { 534 function_start = *pc - offset; 535 registers_on_stack = 1; 536 break; 537 } 538 539 /* lui gp, X */ 540 if ((opcode & 0xffff8000) == 0x3c1c0000) { 541 /* 542 * Function might start with this instruction 543 * Keep an eye on "jr ra" and sp correction 544 * with positive value further on 545 */ 546 function_start = *pc - offset; 547 } 548 549 if (function_start) { 550 /* 551 * Stop looking further. Possible end of 552 * function instruction: it means there is no 553 * stack modifications, sp is unchanged 554 */ 555 556 /* [d]addiu sp,sp,X */ 557 if (((opcode & 0xffff8000) == 0x27bd0000) 558 || ((opcode & 0xffff8000) == 0x67bd0000)) 559 break; 560 561 if (opcode == 0x03e00008) 562 break; 563 } 564 565 offset += sizeof(int); 566 } 567 568 if (!function_start) 569 return (-1); 570 571 if (registers_on_stack) { 572 offset = 0; 573 while ((offset < MAX_PROLOGUE_SIZE) 574 && ((function_start + offset) < *pc)) { 575 i.word = 576 dtrace_fuword32((void *)(vm_offset_t)(function_start + offset)); 577 switch (i.JType.op) { 578 case OP_SW: 579 /* look for saved registers on the stack */ 580 if (i.IType.rs != 29) 581 break; 582 /* only restore the first one */ 583 if (mask & (1 << i.IType.rt)) 584 break; 585 mask |= (1 << i.IType.rt); 586 if (i.IType.rt == 31) 587 *ra = dtrace_fuword32((void *)(vm_offset_t)(*sp + (short)i.IType.imm)); 588 break; 589 590 case OP_SD: 591 /* look for saved registers on the stack */ 592 if (i.IType.rs != 29) 593 break; 594 /* only restore the first one */ 595 if (mask & (1 << i.IType.rt)) 596 break; 597 mask |= (1 << i.IType.rt); 598 /* ra */ 599 if (i.IType.rt == 31) 600 *ra = dtrace_fuword64((void *)(vm_offset_t)(*sp + (short)i.IType.imm)); 601 break; 602 603 case OP_ADDI: 604 case OP_ADDIU: 605 case OP_DADDI: 606 case OP_DADDIU: 607 /* look for stack pointer adjustment */ 608 if (i.IType.rs != 29 || i.IType.rt != 29) 609 break; 610 stksize = -((short)i.IType.imm); 611 } 612 613 offset += sizeof(int); 614 615 if (*flags & CPU_DTRACE_FAULT) 616 goto fault; 617 } 618 } 619 620 /* 621 * We reached the end of backtrace 622 */ 623 if (*pc == *ra) 624 return (-1); 625 626 *pc = *ra; 627 *sp += stksize; 628 629 return (0); 630fault: 631 /* 632 * We just got lost in backtrace, no big deal 633 */ 634 *flags &= ~CPU_DTRACE_FAULT; 635 return (-1); 636} 637 638static int 639dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size) 640{ 641 642 if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) { 643 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 644 cpu_core[curcpu].cpuc_dtrace_illval = uaddr; 645 return (0); 646 } 647 648 return (1); 649} 650 651void 652dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size, 653 volatile uint16_t *flags) 654{ 655 if (dtrace_copycheck(uaddr, kaddr, size)) 656 dtrace_copy(uaddr, kaddr, size); 657} 658 659void 660dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size, 661 volatile uint16_t *flags) 662{ 663 if (dtrace_copycheck(uaddr, kaddr, size)) 664 dtrace_copy(kaddr, uaddr, size); 665} 666 667void 668dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, 669 volatile uint16_t *flags) 670{ 671 if (dtrace_copycheck(uaddr, kaddr, size)) 672 dtrace_copystr(uaddr, kaddr, size, flags); 673} 674 675void 676dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size, 677 volatile uint16_t *flags) 678{ 679 if (dtrace_copycheck(uaddr, kaddr, size)) 680 dtrace_copystr(kaddr, uaddr, size, flags); 681} 682 683uint8_t 684dtrace_fuword8(void *uaddr) 685{ 686 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 687 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 688 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 689 return (0); 690 } 691 return (dtrace_fuword8_nocheck(uaddr)); 692} 693 694uint16_t 695dtrace_fuword16(void *uaddr) 696{ 697 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 698 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 699 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 700 return (0); 701 } 702 return (dtrace_fuword16_nocheck(uaddr)); 703} 704 705uint32_t 706dtrace_fuword32(void *uaddr) 707{ 708 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 709 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 710 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 711 return (0); 712 } 713 return (dtrace_fuword32_nocheck(uaddr)); 714} 715 716uint64_t 717dtrace_fuword64(void *uaddr) 718{ 719 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 720 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 721 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 722 return (0); 723 } 724 return (dtrace_fuword64_nocheck(uaddr)); 725} 726