dtrace_isa.c revision 233409
1233409Sgonzo/* 2233409Sgonzo * CDDL HEADER START 3233409Sgonzo * 4233409Sgonzo * The contents of this file are subject to the terms of the 5233409Sgonzo * Common Development and Distribution License, Version 1.0 only 6233409Sgonzo * (the "License"). You may not use this file except in compliance 7233409Sgonzo * with the License. 8233409Sgonzo * 9233409Sgonzo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10233409Sgonzo * or http://www.opensolaris.org/os/licensing. 11233409Sgonzo * See the License for the specific language governing permissions 12233409Sgonzo * and limitations under the License. 13233409Sgonzo * 14233409Sgonzo * When distributing Covered Code, include this CDDL HEADER in each 15233409Sgonzo * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16233409Sgonzo * If applicable, add the following below this CDDL HEADER, with the 17233409Sgonzo * fields enclosed by brackets "[]" replaced with your own identifying 18233409Sgonzo * information: Portions Copyright [yyyy] [name of copyright owner] 19233409Sgonzo * 20233409Sgonzo * CDDL HEADER END 21233409Sgonzo * 22233409Sgonzo * $FreeBSD: head/sys/cddl/dev/dtrace/mips/dtrace_isa.c 233409 2012-03-24 05:14:37Z gonzo $ 23233409Sgonzo */ 24233409Sgonzo/* 25233409Sgonzo * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 26233409Sgonzo * Use is subject to license terms. 27233409Sgonzo */ 28233409Sgonzo#include <sys/cdefs.h> 29233409Sgonzo 30233409Sgonzo#include <sys/param.h> 31233409Sgonzo#include <sys/systm.h> 32233409Sgonzo#include <sys/kernel.h> 33233409Sgonzo#include <sys/stack.h> 34233409Sgonzo#include <sys/pcpu.h> 35233409Sgonzo 36233409Sgonzo#include <machine/frame.h> 37233409Sgonzo#include <machine/md_var.h> 38233409Sgonzo#include <machine/reg.h> 39233409Sgonzo 40233409Sgonzo#include <vm/vm.h> 41233409Sgonzo#include <vm/vm_param.h> 42233409Sgonzo#include <vm/pmap.h> 43233409Sgonzo 44233409Sgonzo#include <machine/db_machdep.h> 45233409Sgonzo#include <machine/md_var.h> 46233409Sgonzo#include <machine/mips_opcode.h> 47233409Sgonzo#include <machine/vmparam.h> 48233409Sgonzo#include <ddb/db_sym.h> 49233409Sgonzo#include <ddb/ddb.h> 50233409Sgonzo#include <sys/kdb.h> 51233409Sgonzo 52233409Sgonzo#include "regset.h" 53233409Sgonzo 54233409Sgonzo#ifdef __mips_n64 55233409Sgonzo#define MIPS_IS_VALID_KERNELADDR(reg) ((((reg) & 3) == 0) && \ 56233409Sgonzo ((vm_offset_t)(reg) >= MIPS_XKPHYS_START)) 57233409Sgonzo#else 58233409Sgonzo#define MIPS_IS_VALID_KERNELADDR(reg) ((((reg) & 3) == 0) && \ 59233409Sgonzo ((vm_offset_t)(reg) >= MIPS_KSEG0_START)) 60233409Sgonzo#endif 61233409Sgonzo 62233409Sgonzo 63233409Sgonzo 64233409Sgonzo/* 65233409Sgonzo * Wee need some reasonable default to prevent backtrace code 66233409Sgonzo * from wandering too far 67233409Sgonzo */ 68233409Sgonzo#define MAX_FUNCTION_SIZE 0x10000 69233409Sgonzo#define MAX_PROLOGUE_SIZE 0x100 70233409Sgonzo 71233409Sgonzouint8_t dtrace_fuword8_nocheck(void *); 72233409Sgonzouint16_t dtrace_fuword16_nocheck(void *); 73233409Sgonzouint32_t dtrace_fuword32_nocheck(void *); 74233409Sgonzouint64_t dtrace_fuword64_nocheck(void *); 75233409Sgonzo 76233409Sgonzostatic int dtrace_next_frame(register_t *pc, register_t *sp, register_t *args, int *valid_args); 77233409Sgonzostatic int dtrace_next_uframe(register_t *pc, register_t *sp, register_t *ra); 78233409Sgonzo 79233409Sgonzovoid 80233409Sgonzodtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, 81233409Sgonzo uint32_t *intrpc) 82233409Sgonzo{ 83233409Sgonzo int depth = 0; 84233409Sgonzo vm_offset_t callpc; 85233409Sgonzo pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller; 86233409Sgonzo register_t sp, ra, pc; 87233409Sgonzo 88233409Sgonzo if (intrpc != 0) 89233409Sgonzo pcstack[depth++] = (pc_t) intrpc; 90233409Sgonzo 91233409Sgonzo aframes++; 92233409Sgonzo 93233409Sgonzo sp = (register_t)(intptr_t)__builtin_frame_address(0); 94233409Sgonzo ra = (register_t)(intptr_t)__builtin_return_address(0); 95233409Sgonzo 96233409Sgonzo __asm __volatile( 97233409Sgonzo "jal 99f\n" 98233409Sgonzo "nop\n" 99233409Sgonzo "99:\n" 100233409Sgonzo "move %0, $31\n" /* get ra */ 101233409Sgonzo "move $31, %1\n" /* restore ra */ 102233409Sgonzo : "=r" (pc) 103233409Sgonzo : "r" (ra)); 104233409Sgonzo 105233409Sgonzo while (depth < pcstack_limit) { 106233409Sgonzo 107233409Sgonzo callpc = pc; 108233409Sgonzo 109233409Sgonzo if (aframes > 0) { 110233409Sgonzo aframes--; 111233409Sgonzo if ((aframes == 0) && (caller != 0)) { 112233409Sgonzo pcstack[depth++] = caller; 113233409Sgonzo } 114233409Sgonzo } 115233409Sgonzo else { 116233409Sgonzo pcstack[depth++] = callpc; 117233409Sgonzo } 118233409Sgonzo 119233409Sgonzo if (dtrace_next_frame(&pc, &sp, NULL, NULL) < 0) 120233409Sgonzo break; 121233409Sgonzo } 122233409Sgonzo 123233409Sgonzo for (; depth < pcstack_limit; depth++) { 124233409Sgonzo pcstack[depth] = 0; 125233409Sgonzo } 126233409Sgonzo} 127233409Sgonzo 128233409Sgonzovoid 129233409Sgonzodtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) 130233409Sgonzo{ 131233409Sgonzo proc_t *p = curproc; 132233409Sgonzo struct trapframe *tf; 133233409Sgonzo register_t sp, ra, pc; 134233409Sgonzo volatile uint16_t *flags = 135233409Sgonzo (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 136233409Sgonzo 137233409Sgonzo if (*flags & CPU_DTRACE_FAULT) 138233409Sgonzo return; 139233409Sgonzo 140233409Sgonzo if (pcstack_limit <= 0) 141233409Sgonzo return; 142233409Sgonzo 143233409Sgonzo /* 144233409Sgonzo * If there's no user context we still need to zero the stack. 145233409Sgonzo */ 146233409Sgonzo if (p == NULL || (tf = curthread->td_frame) == NULL) 147233409Sgonzo goto zero; 148233409Sgonzo 149233409Sgonzo *pcstack++ = (uint64_t)p->p_pid; 150233409Sgonzo pcstack_limit--; 151233409Sgonzo 152233409Sgonzo if (pcstack_limit <= 0) 153233409Sgonzo return; 154233409Sgonzo 155233409Sgonzo pc = (uint64_t)tf->pc; 156233409Sgonzo sp = (uint64_t)tf->sp; 157233409Sgonzo ra = (uint64_t)tf->ra; 158233409Sgonzo *pcstack++ = (uint64_t)tf->pc; 159233409Sgonzo 160233409Sgonzo /* 161233409Sgonzo * Unwind, and unwind, and unwind 162233409Sgonzo */ 163233409Sgonzo while (1) { 164233409Sgonzo if (dtrace_next_uframe(&pc, &sp, &ra) < 0) 165233409Sgonzo break; 166233409Sgonzo 167233409Sgonzo *pcstack++ = pc; 168233409Sgonzo pcstack_limit--; 169233409Sgonzo 170233409Sgonzo if (pcstack_limit <= 0) 171233409Sgonzo break; 172233409Sgonzo } 173233409Sgonzo 174233409Sgonzozero: 175233409Sgonzo while (pcstack_limit-- > 0) 176233409Sgonzo *pcstack++ = 0; 177233409Sgonzo} 178233409Sgonzo 179233409Sgonzoint 180233409Sgonzodtrace_getustackdepth(void) 181233409Sgonzo{ 182233409Sgonzo int n = 0; 183233409Sgonzo proc_t *p = curproc; 184233409Sgonzo struct trapframe *tf; 185233409Sgonzo register_t sp, ra, pc; 186233409Sgonzo volatile uint16_t *flags = 187233409Sgonzo (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 188233409Sgonzo 189233409Sgonzo if (*flags & CPU_DTRACE_FAULT) 190233409Sgonzo return (0); 191233409Sgonzo 192233409Sgonzo if (p == NULL || (tf = curthread->td_frame) == NULL) 193233409Sgonzo return (0); 194233409Sgonzo 195233409Sgonzo pc = (uint64_t)tf->pc; 196233409Sgonzo sp = (uint64_t)tf->sp; 197233409Sgonzo ra = (uint64_t)tf->ra; 198233409Sgonzo n++; 199233409Sgonzo 200233409Sgonzo /* 201233409Sgonzo * Unwind, and unwind, and unwind 202233409Sgonzo */ 203233409Sgonzo while (1) { 204233409Sgonzo if (dtrace_next_uframe(&pc, &sp, &ra) < 0) 205233409Sgonzo break; 206233409Sgonzo n++; 207233409Sgonzo } 208233409Sgonzo 209233409Sgonzo return (n); 210233409Sgonzo} 211233409Sgonzo 212233409Sgonzovoid 213233409Sgonzodtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) 214233409Sgonzo{ 215233409Sgonzo printf("IMPLEMENT ME: %s\n", __func__); 216233409Sgonzo} 217233409Sgonzo 218233409Sgonzo/*ARGSUSED*/ 219233409Sgonzouint64_t 220233409Sgonzodtrace_getarg(int arg, int aframes) 221233409Sgonzo{ 222233409Sgonzo int i; 223233409Sgonzo register_t sp, ra, pc; 224233409Sgonzo /* XXX: Fix this ugly code */ 225233409Sgonzo register_t args[8]; 226233409Sgonzo int valid[8]; 227233409Sgonzo 228233409Sgonzo sp = (register_t)(intptr_t)__builtin_frame_address(0); 229233409Sgonzo ra = (register_t)(intptr_t)__builtin_return_address(0); 230233409Sgonzo 231233409Sgonzo __asm __volatile( 232233409Sgonzo "jal 99f\n" 233233409Sgonzo "nop\n" 234233409Sgonzo "99:\n" 235233409Sgonzo "move %0, $31\n" /* get ra */ 236233409Sgonzo "move $31, %1\n" /* restore ra */ 237233409Sgonzo : "=r" (pc) 238233409Sgonzo : "r" (ra)); 239233409Sgonzo 240233409Sgonzo for (i = 0; i <= aframes + 1; i++) { 241233409Sgonzo if (dtrace_next_frame(&pc, &sp, args, valid) < 0) { 242233409Sgonzo printf("%s: stack ends at frame #%d\n", __func__, i); 243233409Sgonzo return (0); 244233409Sgonzo } 245233409Sgonzo } 246233409Sgonzo 247233409Sgonzo if (arg < 8) { 248233409Sgonzo if (valid[arg]) 249233409Sgonzo return (args[arg]); 250233409Sgonzo else 251233409Sgonzo printf("%s: request arg%d is not valid\n", __func__, arg); 252233409Sgonzo } 253233409Sgonzo 254233409Sgonzo return (0); 255233409Sgonzo} 256233409Sgonzo 257233409Sgonzoint 258233409Sgonzodtrace_getstackdepth(int aframes) 259233409Sgonzo{ 260233409Sgonzo register_t sp, ra, pc; 261233409Sgonzo int depth = 0; 262233409Sgonzo 263233409Sgonzo sp = (register_t)(intptr_t)__builtin_frame_address(0); 264233409Sgonzo ra = (register_t)(intptr_t)__builtin_return_address(0); 265233409Sgonzo 266233409Sgonzo __asm __volatile( 267233409Sgonzo "jal 99f\n" 268233409Sgonzo "nop\n" 269233409Sgonzo "99:\n" 270233409Sgonzo "move %0, $31\n" /* get ra */ 271233409Sgonzo "move $31, %1\n" /* restore ra */ 272233409Sgonzo : "=r" (pc) 273233409Sgonzo : "r" (ra)); 274233409Sgonzo 275233409Sgonzo for (;;) { 276233409Sgonzo if (dtrace_next_frame(&pc, &sp, NULL, NULL) < 0) 277233409Sgonzo break; 278233409Sgonzo depth++; 279233409Sgonzo } 280233409Sgonzo 281233409Sgonzo if (depth < aframes) 282233409Sgonzo return 0; 283233409Sgonzo else 284233409Sgonzo return depth - aframes; 285233409Sgonzo} 286233409Sgonzo 287233409Sgonzoulong_t 288233409Sgonzodtrace_getreg(struct trapframe *rp, uint_t reg) 289233409Sgonzo{ 290233409Sgonzo 291233409Sgonzo return (0); 292233409Sgonzo} 293233409Sgonzo 294233409Sgonzostatic int 295233409Sgonzodtrace_next_frame(register_t *pc, register_t *sp, 296233409Sgonzo register_t *args, int *valid_args) 297233409Sgonzo{ 298233409Sgonzo InstFmt i; 299233409Sgonzo /* 300233409Sgonzo * Arrays for a0..a3 registers and flags if content 301233409Sgonzo * of these registers is valid, e.g. obtained from the stack 302233409Sgonzo */ 303233409Sgonzo uintptr_t va; 304233409Sgonzo unsigned instr, mask; 305233409Sgonzo unsigned int frames = 0; 306233409Sgonzo int more, stksize; 307233409Sgonzo register_t ra = 0; 308233409Sgonzo int arg, r; 309233409Sgonzo vm_offset_t addr; 310233409Sgonzo 311233409Sgonzo /* 312233409Sgonzo * Invalidate arguments values 313233409Sgonzo */ 314233409Sgonzo if (valid_args) { 315233409Sgonzo for (r = 0; r < 8; r++) 316233409Sgonzo valid_args[r] = 0; 317233409Sgonzo } 318233409Sgonzo 319233409Sgonzo /* Jump here after a nonstandard (interrupt handler) frame */ 320233409Sgonzo stksize = 0; 321233409Sgonzo if (frames++ > 100) { 322233409Sgonzo /* return breaks stackframe-size heuristics with gcc -O2 */ 323233409Sgonzo goto error; /* XXX */ 324233409Sgonzo } 325233409Sgonzo 326233409Sgonzo /* check for bad SP: could foul up next frame */ 327233409Sgonzo if (!MIPS_IS_VALID_KERNELADDR(*sp)) { 328233409Sgonzo goto error; 329233409Sgonzo } 330233409Sgonzo 331233409Sgonzo /* check for bad PC */ 332233409Sgonzo if (!MIPS_IS_VALID_KERNELADDR(*pc)) { 333233409Sgonzo goto error; 334233409Sgonzo } 335233409Sgonzo 336233409Sgonzo /* 337233409Sgonzo * Find the beginning of the current subroutine by scanning 338233409Sgonzo * backwards from the current PC for the end of the previous 339233409Sgonzo * subroutine. 340233409Sgonzo */ 341233409Sgonzo va = *pc - sizeof(int); 342233409Sgonzo while (1) { 343233409Sgonzo instr = kdbpeek((int *)va); 344233409Sgonzo 345233409Sgonzo /* [d]addiu sp,sp,-X */ 346233409Sgonzo if (((instr & 0xffff8000) == 0x27bd8000) 347233409Sgonzo || ((instr & 0xffff8000) == 0x67bd8000)) 348233409Sgonzo break; 349233409Sgonzo 350233409Sgonzo /* jr ra */ 351233409Sgonzo if (instr == 0x03e00008) { 352233409Sgonzo /* skip over branch-delay slot instruction */ 353233409Sgonzo va += 2 * sizeof(int); 354233409Sgonzo break; 355233409Sgonzo } 356233409Sgonzo 357233409Sgonzo va -= sizeof(int); 358233409Sgonzo } 359233409Sgonzo 360233409Sgonzo /* skip over nulls which might separate .o files */ 361233409Sgonzo while ((instr = kdbpeek((int *)va)) == 0) 362233409Sgonzo va += sizeof(int); 363233409Sgonzo 364233409Sgonzo /* scan forwards to find stack size and any saved registers */ 365233409Sgonzo stksize = 0; 366233409Sgonzo more = 3; 367233409Sgonzo mask = 0; 368233409Sgonzo for (; more; va += sizeof(int), 369233409Sgonzo more = (more == 3) ? 3 : more - 1) { 370233409Sgonzo /* stop if hit our current position */ 371233409Sgonzo if (va >= *pc) 372233409Sgonzo break; 373233409Sgonzo instr = kdbpeek((int *)va); 374233409Sgonzo i.word = instr; 375233409Sgonzo switch (i.JType.op) { 376233409Sgonzo case OP_SPECIAL: 377233409Sgonzo switch (i.RType.func) { 378233409Sgonzo case OP_JR: 379233409Sgonzo case OP_JALR: 380233409Sgonzo more = 2; /* stop after next instruction */ 381233409Sgonzo break; 382233409Sgonzo 383233409Sgonzo case OP_SYSCALL: 384233409Sgonzo case OP_BREAK: 385233409Sgonzo more = 1; /* stop now */ 386233409Sgonzo }; 387233409Sgonzo break; 388233409Sgonzo 389233409Sgonzo case OP_BCOND: 390233409Sgonzo case OP_J: 391233409Sgonzo case OP_JAL: 392233409Sgonzo case OP_BEQ: 393233409Sgonzo case OP_BNE: 394233409Sgonzo case OP_BLEZ: 395233409Sgonzo case OP_BGTZ: 396233409Sgonzo more = 2; /* stop after next instruction */ 397233409Sgonzo break; 398233409Sgonzo 399233409Sgonzo case OP_COP0: 400233409Sgonzo case OP_COP1: 401233409Sgonzo case OP_COP2: 402233409Sgonzo case OP_COP3: 403233409Sgonzo switch (i.RType.rs) { 404233409Sgonzo case OP_BCx: 405233409Sgonzo case OP_BCy: 406233409Sgonzo more = 2; /* stop after next instruction */ 407233409Sgonzo }; 408233409Sgonzo break; 409233409Sgonzo 410233409Sgonzo case OP_SW: 411233409Sgonzo /* look for saved registers on the stack */ 412233409Sgonzo if (i.IType.rs != 29) 413233409Sgonzo break; 414233409Sgonzo /* only restore the first one */ 415233409Sgonzo if (mask & (1 << i.IType.rt)) 416233409Sgonzo break; 417233409Sgonzo mask |= (1 << i.IType.rt); 418233409Sgonzo addr = (vm_offset_t)(*sp + (short)i.IType.imm); 419233409Sgonzo switch (i.IType.rt) { 420233409Sgonzo case 4:/* a0 */ 421233409Sgonzo case 5:/* a1 */ 422233409Sgonzo case 6:/* a2 */ 423233409Sgonzo case 7:/* a3 */ 424233409Sgonzo#if defined(__mips_n64) || defined(__mips_n32) 425233409Sgonzo case 8:/* a4 */ 426233409Sgonzo case 9:/* a5 */ 427233409Sgonzo case 10:/* a6 */ 428233409Sgonzo case 11:/* a7 */ 429233409Sgonzo#endif 430233409Sgonzo arg = i.IType.rt - 4; 431233409Sgonzo if (args) 432233409Sgonzo args[arg] = kdbpeek((int*)addr); 433233409Sgonzo if (valid_args) 434233409Sgonzo valid_args[arg] = 1; 435233409Sgonzo break; 436233409Sgonzo case 31: /* ra */ 437233409Sgonzo ra = kdbpeek((int *)addr); 438233409Sgonzo } 439233409Sgonzo break; 440233409Sgonzo 441233409Sgonzo case OP_SD: 442233409Sgonzo /* look for saved registers on the stack */ 443233409Sgonzo if (i.IType.rs != 29) 444233409Sgonzo break; 445233409Sgonzo /* only restore the first one */ 446233409Sgonzo if (mask & (1 << i.IType.rt)) 447233409Sgonzo break; 448233409Sgonzo mask |= (1 << i.IType.rt); 449233409Sgonzo addr = (vm_offset_t)(*sp + (short)i.IType.imm); 450233409Sgonzo switch (i.IType.rt) { 451233409Sgonzo case 4:/* a0 */ 452233409Sgonzo case 5:/* a1 */ 453233409Sgonzo case 6:/* a2 */ 454233409Sgonzo case 7:/* a3 */ 455233409Sgonzo#if defined(__mips_n64) || defined(__mips_n32) 456233409Sgonzo case 8:/* a4 */ 457233409Sgonzo case 9:/* a5 */ 458233409Sgonzo case 10:/* a6 */ 459233409Sgonzo case 11:/* a7 */ 460233409Sgonzo#endif 461233409Sgonzo arg = i.IType.rt - 4; 462233409Sgonzo if (args) 463233409Sgonzo args[arg] = kdbpeekd((int *)addr); 464233409Sgonzo if (valid_args) 465233409Sgonzo valid_args[arg] = 1; 466233409Sgonzo break; 467233409Sgonzo 468233409Sgonzo case 31: /* ra */ 469233409Sgonzo ra = kdbpeekd((int *)addr); 470233409Sgonzo } 471233409Sgonzo break; 472233409Sgonzo 473233409Sgonzo case OP_ADDI: 474233409Sgonzo case OP_ADDIU: 475233409Sgonzo case OP_DADDI: 476233409Sgonzo case OP_DADDIU: 477233409Sgonzo /* look for stack pointer adjustment */ 478233409Sgonzo if (i.IType.rs != 29 || i.IType.rt != 29) 479233409Sgonzo break; 480233409Sgonzo stksize = -((short)i.IType.imm); 481233409Sgonzo } 482233409Sgonzo } 483233409Sgonzo 484233409Sgonzo if (!MIPS_IS_VALID_KERNELADDR(ra)) 485233409Sgonzo return (-1); 486233409Sgonzo 487233409Sgonzo *pc = ra; 488233409Sgonzo *sp += stksize; 489233409Sgonzo 490233409Sgonzo return (0); 491233409Sgonzoerror: 492233409Sgonzo return (-1); 493233409Sgonzo} 494233409Sgonzo 495233409Sgonzostatic int 496233409Sgonzodtrace_next_uframe(register_t *pc, register_t *sp, register_t *ra) 497233409Sgonzo{ 498233409Sgonzo int offset, registers_on_stack; 499233409Sgonzo uint32_t opcode, mask; 500233409Sgonzo register_t function_start; 501233409Sgonzo int stksize; 502233409Sgonzo InstFmt i; 503233409Sgonzo 504233409Sgonzo registers_on_stack = 0; 505233409Sgonzo mask = 0; 506233409Sgonzo function_start = 0; 507233409Sgonzo offset = 0; 508233409Sgonzo stksize = 0; 509233409Sgonzo 510233409Sgonzo while (offset < MAX_FUNCTION_SIZE) { 511233409Sgonzo opcode = dtrace_fuword32((void *)(vm_offset_t)(*pc - offset)); 512233409Sgonzo 513233409Sgonzo /* [d]addiu sp, sp, -X*/ 514233409Sgonzo if (((opcode & 0xffff8000) == 0x27bd8000) 515233409Sgonzo || ((opcode & 0xffff8000) == 0x67bd8000)) { 516233409Sgonzo function_start = *pc - offset; 517233409Sgonzo registers_on_stack = 1; 518233409Sgonzo break; 519233409Sgonzo } 520233409Sgonzo 521233409Sgonzo /* lui gp, X */ 522233409Sgonzo if ((opcode & 0xffff8000) == 0x3c1c0000) { 523233409Sgonzo /* 524233409Sgonzo * Function might start with this instruction 525233409Sgonzo * Keep an eye on "jr ra" and sp correction 526233409Sgonzo * with positive value further on 527233409Sgonzo */ 528233409Sgonzo function_start = *pc - offset; 529233409Sgonzo } 530233409Sgonzo 531233409Sgonzo if (function_start) { 532233409Sgonzo /* 533233409Sgonzo * Stop looking further. Possible end of 534233409Sgonzo * function instruction: it means there is no 535233409Sgonzo * stack modifications, sp is unchanged 536233409Sgonzo */ 537233409Sgonzo 538233409Sgonzo /* [d]addiu sp,sp,X */ 539233409Sgonzo if (((opcode & 0xffff8000) == 0x27bd0000) 540233409Sgonzo || ((opcode & 0xffff8000) == 0x67bd0000)) 541233409Sgonzo break; 542233409Sgonzo 543233409Sgonzo if (opcode == 0x03e00008) 544233409Sgonzo break; 545233409Sgonzo } 546233409Sgonzo 547233409Sgonzo offset += sizeof(int); 548233409Sgonzo } 549233409Sgonzo 550233409Sgonzo if (!function_start) 551233409Sgonzo return (-1); 552233409Sgonzo 553233409Sgonzo if (registers_on_stack) { 554233409Sgonzo offset = 0; 555233409Sgonzo while ((offset < MAX_PROLOGUE_SIZE) 556233409Sgonzo && ((function_start + offset) < *pc)) { 557233409Sgonzo i.word = 558233409Sgonzo dtrace_fuword32((void *)(vm_offset_t)(function_start + offset)); 559233409Sgonzo switch (i.JType.op) { 560233409Sgonzo case OP_SW: 561233409Sgonzo /* look for saved registers on the stack */ 562233409Sgonzo if (i.IType.rs != 29) 563233409Sgonzo break; 564233409Sgonzo /* only restore the first one */ 565233409Sgonzo if (mask & (1 << i.IType.rt)) 566233409Sgonzo break; 567233409Sgonzo mask |= (1 << i.IType.rt); 568233409Sgonzo if (i.IType.rt == 31) 569233409Sgonzo *ra = dtrace_fuword32((void *)(vm_offset_t)(*sp + (short)i.IType.imm)); 570233409Sgonzo break; 571233409Sgonzo 572233409Sgonzo case OP_SD: 573233409Sgonzo /* look for saved registers on the stack */ 574233409Sgonzo if (i.IType.rs != 29) 575233409Sgonzo break; 576233409Sgonzo /* only restore the first one */ 577233409Sgonzo if (mask & (1 << i.IType.rt)) 578233409Sgonzo break; 579233409Sgonzo mask |= (1 << i.IType.rt); 580233409Sgonzo /* ra */ 581233409Sgonzo if (i.IType.rt == 31) 582233409Sgonzo *ra = dtrace_fuword64((void *)(vm_offset_t)(*sp + (short)i.IType.imm)); 583233409Sgonzo break; 584233409Sgonzo 585233409Sgonzo case OP_ADDI: 586233409Sgonzo case OP_ADDIU: 587233409Sgonzo case OP_DADDI: 588233409Sgonzo case OP_DADDIU: 589233409Sgonzo /* look for stack pointer adjustment */ 590233409Sgonzo if (i.IType.rs != 29 || i.IType.rt != 29) 591233409Sgonzo break; 592233409Sgonzo stksize = -((short)i.IType.imm); 593233409Sgonzo } 594233409Sgonzo 595233409Sgonzo offset += sizeof(int); 596233409Sgonzo } 597233409Sgonzo } 598233409Sgonzo 599233409Sgonzo /* 600233409Sgonzo * We reached the end of backtrace 601233409Sgonzo */ 602233409Sgonzo if (*pc == *ra) 603233409Sgonzo return (-1); 604233409Sgonzo 605233409Sgonzo *pc = *ra; 606233409Sgonzo *sp += stksize; 607233409Sgonzo 608233409Sgonzo return (0); 609233409Sgonzo} 610233409Sgonzo 611233409Sgonzostatic int 612233409Sgonzodtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size) 613233409Sgonzo{ 614233409Sgonzo 615233409Sgonzo if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) { 616233409Sgonzo DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 617233409Sgonzo cpu_core[curcpu].cpuc_dtrace_illval = uaddr; 618233409Sgonzo return (0); 619233409Sgonzo } 620233409Sgonzo 621233409Sgonzo return (1); 622233409Sgonzo} 623233409Sgonzo 624233409Sgonzovoid 625233409Sgonzodtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size, 626233409Sgonzo volatile uint16_t *flags) 627233409Sgonzo{ 628233409Sgonzo if (dtrace_copycheck(uaddr, kaddr, size)) 629233409Sgonzo dtrace_copy(uaddr, kaddr, size); 630233409Sgonzo} 631233409Sgonzo 632233409Sgonzovoid 633233409Sgonzodtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size, 634233409Sgonzo volatile uint16_t *flags) 635233409Sgonzo{ 636233409Sgonzo if (dtrace_copycheck(uaddr, kaddr, size)) 637233409Sgonzo dtrace_copy(kaddr, uaddr, size); 638233409Sgonzo} 639233409Sgonzo 640233409Sgonzovoid 641233409Sgonzodtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, 642233409Sgonzo volatile uint16_t *flags) 643233409Sgonzo{ 644233409Sgonzo if (dtrace_copycheck(uaddr, kaddr, size)) 645233409Sgonzo dtrace_copystr(uaddr, kaddr, size, flags); 646233409Sgonzo} 647233409Sgonzo 648233409Sgonzovoid 649233409Sgonzodtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size, 650233409Sgonzo volatile uint16_t *flags) 651233409Sgonzo{ 652233409Sgonzo if (dtrace_copycheck(uaddr, kaddr, size)) 653233409Sgonzo dtrace_copystr(kaddr, uaddr, size, flags); 654233409Sgonzo} 655233409Sgonzo 656233409Sgonzouint8_t 657233409Sgonzodtrace_fuword8(void *uaddr) 658233409Sgonzo{ 659233409Sgonzo if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 660233409Sgonzo DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 661233409Sgonzo cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 662233409Sgonzo return (0); 663233409Sgonzo } 664233409Sgonzo return (dtrace_fuword8_nocheck(uaddr)); 665233409Sgonzo} 666233409Sgonzo 667233409Sgonzouint16_t 668233409Sgonzodtrace_fuword16(void *uaddr) 669233409Sgonzo{ 670233409Sgonzo if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 671233409Sgonzo DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 672233409Sgonzo cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 673233409Sgonzo return (0); 674233409Sgonzo } 675233409Sgonzo return (dtrace_fuword16_nocheck(uaddr)); 676233409Sgonzo} 677233409Sgonzo 678233409Sgonzouint32_t 679233409Sgonzodtrace_fuword32(void *uaddr) 680233409Sgonzo{ 681233409Sgonzo if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 682233409Sgonzo DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 683233409Sgonzo cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 684233409Sgonzo return (0); 685233409Sgonzo } 686233409Sgonzo return (dtrace_fuword32_nocheck(uaddr)); 687233409Sgonzo} 688233409Sgonzo 689233409Sgonzouint64_t 690233409Sgonzodtrace_fuword64(void *uaddr) 691233409Sgonzo{ 692233409Sgonzo if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 693233409Sgonzo DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 694233409Sgonzo cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 695233409Sgonzo return (0); 696233409Sgonzo } 697233409Sgonzo return (dtrace_fuword64_nocheck(uaddr)); 698233409Sgonzo} 699