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