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: releng/11.0/sys/cddl/dev/dtrace/mips/dtrace_isa.c 295882 2016-02-22 09:08:04Z skra $ 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 <ddb/db_sym.h> 48233409Sgonzo#include <ddb/ddb.h> 49233409Sgonzo#include <sys/kdb.h> 50233409Sgonzo 51233409Sgonzo#include "regset.h" 52233409Sgonzo 53233409Sgonzo#ifdef __mips_n64 54233409Sgonzo#define MIPS_IS_VALID_KERNELADDR(reg) ((((reg) & 3) == 0) && \ 55233409Sgonzo ((vm_offset_t)(reg) >= MIPS_XKPHYS_START)) 56233409Sgonzo#else 57233409Sgonzo#define MIPS_IS_VALID_KERNELADDR(reg) ((((reg) & 3) == 0) && \ 58233409Sgonzo ((vm_offset_t)(reg) >= MIPS_KSEG0_START)) 59233409Sgonzo#endif 60233409Sgonzo 61233409Sgonzo 62233409Sgonzo 63233409Sgonzo/* 64233409Sgonzo * Wee need some reasonable default to prevent backtrace code 65233409Sgonzo * from wandering too far 66233409Sgonzo */ 67233409Sgonzo#define MAX_FUNCTION_SIZE 0x10000 68233409Sgonzo#define MAX_PROLOGUE_SIZE 0x100 69233409Sgonzo 70233409Sgonzouint8_t dtrace_fuword8_nocheck(void *); 71233409Sgonzouint16_t dtrace_fuword16_nocheck(void *); 72233409Sgonzouint32_t dtrace_fuword32_nocheck(void *); 73233409Sgonzouint64_t dtrace_fuword64_nocheck(void *); 74233409Sgonzo 75233409Sgonzostatic int dtrace_next_frame(register_t *pc, register_t *sp, register_t *args, int *valid_args); 76233409Sgonzostatic int dtrace_next_uframe(register_t *pc, register_t *sp, register_t *ra); 77233409Sgonzo 78233409Sgonzovoid 79233409Sgonzodtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, 80233409Sgonzo uint32_t *intrpc) 81233409Sgonzo{ 82233409Sgonzo int depth = 0; 83233409Sgonzo vm_offset_t callpc; 84233409Sgonzo pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller; 85233409Sgonzo register_t sp, ra, pc; 86233409Sgonzo 87233409Sgonzo if (intrpc != 0) 88233409Sgonzo pcstack[depth++] = (pc_t) intrpc; 89233409Sgonzo 90233409Sgonzo aframes++; 91233409Sgonzo 92233409Sgonzo sp = (register_t)(intptr_t)__builtin_frame_address(0); 93233409Sgonzo ra = (register_t)(intptr_t)__builtin_return_address(0); 94233409Sgonzo 95233409Sgonzo __asm __volatile( 96233409Sgonzo "jal 99f\n" 97233409Sgonzo "nop\n" 98233409Sgonzo "99:\n" 99233409Sgonzo "move %0, $31\n" /* get ra */ 100233409Sgonzo "move $31, %1\n" /* restore ra */ 101233409Sgonzo : "=r" (pc) 102233409Sgonzo : "r" (ra)); 103233409Sgonzo 104233409Sgonzo while (depth < pcstack_limit) { 105233409Sgonzo 106233409Sgonzo callpc = pc; 107233409Sgonzo 108233409Sgonzo if (aframes > 0) { 109233409Sgonzo aframes--; 110233409Sgonzo if ((aframes == 0) && (caller != 0)) { 111233409Sgonzo pcstack[depth++] = caller; 112233409Sgonzo } 113233409Sgonzo } 114233409Sgonzo else { 115233409Sgonzo pcstack[depth++] = callpc; 116233409Sgonzo } 117233409Sgonzo 118233409Sgonzo if (dtrace_next_frame(&pc, &sp, NULL, NULL) < 0) 119233409Sgonzo break; 120233409Sgonzo } 121233409Sgonzo 122233409Sgonzo for (; depth < pcstack_limit; depth++) { 123233409Sgonzo pcstack[depth] = 0; 124233409Sgonzo } 125233409Sgonzo} 126233409Sgonzo 127233409Sgonzovoid 128233409Sgonzodtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) 129233409Sgonzo{ 130233409Sgonzo proc_t *p = curproc; 131233409Sgonzo struct trapframe *tf; 132233409Sgonzo register_t sp, ra, pc; 133233409Sgonzo volatile uint16_t *flags = 134233409Sgonzo (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 135233409Sgonzo 136233409Sgonzo if (*flags & CPU_DTRACE_FAULT) 137233409Sgonzo return; 138233409Sgonzo 139233409Sgonzo if (pcstack_limit <= 0) 140233409Sgonzo return; 141233409Sgonzo 142233409Sgonzo /* 143233409Sgonzo * If there's no user context we still need to zero the stack. 144233409Sgonzo */ 145233409Sgonzo if (p == NULL || (tf = curthread->td_frame) == NULL) 146233409Sgonzo goto zero; 147233409Sgonzo 148233409Sgonzo *pcstack++ = (uint64_t)p->p_pid; 149233409Sgonzo pcstack_limit--; 150233409Sgonzo 151233409Sgonzo if (pcstack_limit <= 0) 152233409Sgonzo return; 153233409Sgonzo 154233409Sgonzo pc = (uint64_t)tf->pc; 155233409Sgonzo sp = (uint64_t)tf->sp; 156233409Sgonzo ra = (uint64_t)tf->ra; 157233409Sgonzo *pcstack++ = (uint64_t)tf->pc; 158233409Sgonzo 159233409Sgonzo /* 160233409Sgonzo * Unwind, and unwind, and unwind 161233409Sgonzo */ 162233409Sgonzo while (1) { 163233409Sgonzo if (dtrace_next_uframe(&pc, &sp, &ra) < 0) 164233409Sgonzo break; 165233409Sgonzo 166233409Sgonzo *pcstack++ = pc; 167233409Sgonzo pcstack_limit--; 168233409Sgonzo 169233409Sgonzo if (pcstack_limit <= 0) 170233409Sgonzo break; 171233409Sgonzo } 172233409Sgonzo 173233409Sgonzozero: 174233409Sgonzo while (pcstack_limit-- > 0) 175233409Sgonzo *pcstack++ = 0; 176233409Sgonzo} 177233409Sgonzo 178233409Sgonzoint 179233409Sgonzodtrace_getustackdepth(void) 180233409Sgonzo{ 181233409Sgonzo int n = 0; 182233409Sgonzo proc_t *p = curproc; 183233409Sgonzo struct trapframe *tf; 184233409Sgonzo register_t sp, ra, pc; 185233409Sgonzo volatile uint16_t *flags = 186233409Sgonzo (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 187233409Sgonzo 188233409Sgonzo if (*flags & CPU_DTRACE_FAULT) 189233409Sgonzo return (0); 190233409Sgonzo 191233409Sgonzo if (p == NULL || (tf = curthread->td_frame) == NULL) 192233409Sgonzo return (0); 193233409Sgonzo 194233409Sgonzo pc = (uint64_t)tf->pc; 195233409Sgonzo sp = (uint64_t)tf->sp; 196233409Sgonzo ra = (uint64_t)tf->ra; 197233409Sgonzo n++; 198233409Sgonzo 199233409Sgonzo /* 200233409Sgonzo * Unwind, and unwind, and unwind 201233409Sgonzo */ 202233409Sgonzo while (1) { 203233409Sgonzo if (dtrace_next_uframe(&pc, &sp, &ra) < 0) 204233409Sgonzo break; 205233409Sgonzo n++; 206233409Sgonzo } 207233409Sgonzo 208233409Sgonzo return (n); 209233409Sgonzo} 210233409Sgonzo 211233409Sgonzovoid 212233409Sgonzodtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) 213233409Sgonzo{ 214233409Sgonzo printf("IMPLEMENT ME: %s\n", __func__); 215233409Sgonzo} 216233409Sgonzo 217233409Sgonzo/*ARGSUSED*/ 218233409Sgonzouint64_t 219233409Sgonzodtrace_getarg(int arg, int aframes) 220233409Sgonzo{ 221233409Sgonzo int i; 222233409Sgonzo register_t sp, ra, pc; 223233409Sgonzo /* XXX: Fix this ugly code */ 224233409Sgonzo register_t args[8]; 225233409Sgonzo int valid[8]; 226233409Sgonzo 227233409Sgonzo sp = (register_t)(intptr_t)__builtin_frame_address(0); 228233409Sgonzo ra = (register_t)(intptr_t)__builtin_return_address(0); 229233409Sgonzo 230233409Sgonzo __asm __volatile( 231233409Sgonzo "jal 99f\n" 232233409Sgonzo "nop\n" 233233409Sgonzo "99:\n" 234233409Sgonzo "move %0, $31\n" /* get ra */ 235233409Sgonzo "move $31, %1\n" /* restore ra */ 236233409Sgonzo : "=r" (pc) 237233409Sgonzo : "r" (ra)); 238233409Sgonzo 239233409Sgonzo for (i = 0; i <= aframes + 1; i++) { 240233409Sgonzo if (dtrace_next_frame(&pc, &sp, args, valid) < 0) { 241233409Sgonzo printf("%s: stack ends at frame #%d\n", __func__, i); 242233409Sgonzo return (0); 243233409Sgonzo } 244233409Sgonzo } 245233409Sgonzo 246233409Sgonzo if (arg < 8) { 247233409Sgonzo if (valid[arg]) 248233409Sgonzo return (args[arg]); 249233409Sgonzo else 250233409Sgonzo printf("%s: request arg%d is not valid\n", __func__, arg); 251233409Sgonzo } 252233409Sgonzo 253233409Sgonzo return (0); 254233409Sgonzo} 255233409Sgonzo 256233409Sgonzoint 257233409Sgonzodtrace_getstackdepth(int aframes) 258233409Sgonzo{ 259233409Sgonzo register_t sp, ra, pc; 260233409Sgonzo int depth = 0; 261233409Sgonzo 262233409Sgonzo sp = (register_t)(intptr_t)__builtin_frame_address(0); 263233409Sgonzo ra = (register_t)(intptr_t)__builtin_return_address(0); 264233409Sgonzo 265233409Sgonzo __asm __volatile( 266233409Sgonzo "jal 99f\n" 267233409Sgonzo "nop\n" 268233409Sgonzo "99:\n" 269233409Sgonzo "move %0, $31\n" /* get ra */ 270233409Sgonzo "move $31, %1\n" /* restore ra */ 271233409Sgonzo : "=r" (pc) 272233409Sgonzo : "r" (ra)); 273233409Sgonzo 274233409Sgonzo for (;;) { 275233409Sgonzo if (dtrace_next_frame(&pc, &sp, NULL, NULL) < 0) 276233409Sgonzo break; 277233409Sgonzo depth++; 278233409Sgonzo } 279233409Sgonzo 280233409Sgonzo if (depth < aframes) 281233409Sgonzo return 0; 282233409Sgonzo else 283233409Sgonzo return depth - aframes; 284233409Sgonzo} 285233409Sgonzo 286233409Sgonzoulong_t 287233409Sgonzodtrace_getreg(struct trapframe *rp, uint_t reg) 288233409Sgonzo{ 289233409Sgonzo 290233409Sgonzo return (0); 291233409Sgonzo} 292233409Sgonzo 293233409Sgonzostatic int 294233409Sgonzodtrace_next_frame(register_t *pc, register_t *sp, 295233409Sgonzo register_t *args, int *valid_args) 296233409Sgonzo{ 297233409Sgonzo InstFmt i; 298233409Sgonzo /* 299233409Sgonzo * Arrays for a0..a3 registers and flags if content 300233409Sgonzo * of these registers is valid, e.g. obtained from the stack 301233409Sgonzo */ 302233409Sgonzo uintptr_t va; 303233409Sgonzo unsigned instr, mask; 304233409Sgonzo unsigned int frames = 0; 305233409Sgonzo int more, stksize; 306233409Sgonzo register_t ra = 0; 307233409Sgonzo int arg, r; 308233409Sgonzo vm_offset_t addr; 309233409Sgonzo 310233409Sgonzo /* 311233409Sgonzo * Invalidate arguments values 312233409Sgonzo */ 313233409Sgonzo if (valid_args) { 314233409Sgonzo for (r = 0; r < 8; r++) 315233409Sgonzo valid_args[r] = 0; 316233409Sgonzo } 317233409Sgonzo 318233409Sgonzo /* Jump here after a nonstandard (interrupt handler) frame */ 319233409Sgonzo stksize = 0; 320233409Sgonzo if (frames++ > 100) { 321233409Sgonzo /* return breaks stackframe-size heuristics with gcc -O2 */ 322233409Sgonzo goto error; /* XXX */ 323233409Sgonzo } 324233409Sgonzo 325233409Sgonzo /* check for bad SP: could foul up next frame */ 326233409Sgonzo if (!MIPS_IS_VALID_KERNELADDR(*sp)) { 327233409Sgonzo goto error; 328233409Sgonzo } 329233409Sgonzo 330233409Sgonzo /* check for bad PC */ 331233409Sgonzo if (!MIPS_IS_VALID_KERNELADDR(*pc)) { 332233409Sgonzo goto error; 333233409Sgonzo } 334233409Sgonzo 335233409Sgonzo /* 336233409Sgonzo * Find the beginning of the current subroutine by scanning 337233409Sgonzo * backwards from the current PC for the end of the previous 338233409Sgonzo * subroutine. 339233409Sgonzo */ 340233409Sgonzo va = *pc - sizeof(int); 341233409Sgonzo while (1) { 342233409Sgonzo instr = kdbpeek((int *)va); 343233409Sgonzo 344233409Sgonzo /* [d]addiu sp,sp,-X */ 345233409Sgonzo if (((instr & 0xffff8000) == 0x27bd8000) 346233409Sgonzo || ((instr & 0xffff8000) == 0x67bd8000)) 347233409Sgonzo break; 348233409Sgonzo 349233409Sgonzo /* jr ra */ 350233409Sgonzo if (instr == 0x03e00008) { 351233409Sgonzo /* skip over branch-delay slot instruction */ 352233409Sgonzo va += 2 * sizeof(int); 353233409Sgonzo break; 354233409Sgonzo } 355233409Sgonzo 356233409Sgonzo va -= sizeof(int); 357233409Sgonzo } 358233409Sgonzo 359233409Sgonzo /* skip over nulls which might separate .o files */ 360233409Sgonzo while ((instr = kdbpeek((int *)va)) == 0) 361233409Sgonzo va += sizeof(int); 362233409Sgonzo 363233409Sgonzo /* scan forwards to find stack size and any saved registers */ 364233409Sgonzo stksize = 0; 365233409Sgonzo more = 3; 366233409Sgonzo mask = 0; 367233409Sgonzo for (; more; va += sizeof(int), 368233409Sgonzo more = (more == 3) ? 3 : more - 1) { 369233409Sgonzo /* stop if hit our current position */ 370233409Sgonzo if (va >= *pc) 371233409Sgonzo break; 372233409Sgonzo instr = kdbpeek((int *)va); 373233409Sgonzo i.word = instr; 374233409Sgonzo switch (i.JType.op) { 375233409Sgonzo case OP_SPECIAL: 376233409Sgonzo switch (i.RType.func) { 377233409Sgonzo case OP_JR: 378233409Sgonzo case OP_JALR: 379233409Sgonzo more = 2; /* stop after next instruction */ 380233409Sgonzo break; 381233409Sgonzo 382233409Sgonzo case OP_SYSCALL: 383233409Sgonzo case OP_BREAK: 384233409Sgonzo more = 1; /* stop now */ 385233409Sgonzo }; 386233409Sgonzo break; 387233409Sgonzo 388233409Sgonzo case OP_BCOND: 389233409Sgonzo case OP_J: 390233409Sgonzo case OP_JAL: 391233409Sgonzo case OP_BEQ: 392233409Sgonzo case OP_BNE: 393233409Sgonzo case OP_BLEZ: 394233409Sgonzo case OP_BGTZ: 395233409Sgonzo more = 2; /* stop after next instruction */ 396233409Sgonzo break; 397233409Sgonzo 398233409Sgonzo case OP_COP0: 399233409Sgonzo case OP_COP1: 400233409Sgonzo case OP_COP2: 401233409Sgonzo case OP_COP3: 402233409Sgonzo switch (i.RType.rs) { 403233409Sgonzo case OP_BCx: 404233409Sgonzo case OP_BCy: 405233409Sgonzo more = 2; /* stop after next instruction */ 406233409Sgonzo }; 407233409Sgonzo break; 408233409Sgonzo 409233409Sgonzo case OP_SW: 410233409Sgonzo /* look for saved registers on the stack */ 411233409Sgonzo if (i.IType.rs != 29) 412233409Sgonzo break; 413233409Sgonzo /* only restore the first one */ 414233409Sgonzo if (mask & (1 << i.IType.rt)) 415233409Sgonzo break; 416233409Sgonzo mask |= (1 << i.IType.rt); 417233409Sgonzo addr = (vm_offset_t)(*sp + (short)i.IType.imm); 418233409Sgonzo switch (i.IType.rt) { 419233409Sgonzo case 4:/* a0 */ 420233409Sgonzo case 5:/* a1 */ 421233409Sgonzo case 6:/* a2 */ 422233409Sgonzo case 7:/* a3 */ 423233409Sgonzo#if defined(__mips_n64) || defined(__mips_n32) 424233409Sgonzo case 8:/* a4 */ 425233409Sgonzo case 9:/* a5 */ 426233409Sgonzo case 10:/* a6 */ 427233409Sgonzo case 11:/* a7 */ 428233409Sgonzo#endif 429233409Sgonzo arg = i.IType.rt - 4; 430233409Sgonzo if (args) 431233409Sgonzo args[arg] = kdbpeek((int*)addr); 432233409Sgonzo if (valid_args) 433233409Sgonzo valid_args[arg] = 1; 434233409Sgonzo break; 435233409Sgonzo case 31: /* ra */ 436233409Sgonzo ra = kdbpeek((int *)addr); 437233409Sgonzo } 438233409Sgonzo break; 439233409Sgonzo 440233409Sgonzo case OP_SD: 441233409Sgonzo /* look for saved registers on the stack */ 442233409Sgonzo if (i.IType.rs != 29) 443233409Sgonzo break; 444233409Sgonzo /* only restore the first one */ 445233409Sgonzo if (mask & (1 << i.IType.rt)) 446233409Sgonzo break; 447233409Sgonzo mask |= (1 << i.IType.rt); 448233409Sgonzo addr = (vm_offset_t)(*sp + (short)i.IType.imm); 449233409Sgonzo switch (i.IType.rt) { 450233409Sgonzo case 4:/* a0 */ 451233409Sgonzo case 5:/* a1 */ 452233409Sgonzo case 6:/* a2 */ 453233409Sgonzo case 7:/* a3 */ 454233409Sgonzo#if defined(__mips_n64) || defined(__mips_n32) 455233409Sgonzo case 8:/* a4 */ 456233409Sgonzo case 9:/* a5 */ 457233409Sgonzo case 10:/* a6 */ 458233409Sgonzo case 11:/* a7 */ 459233409Sgonzo#endif 460233409Sgonzo arg = i.IType.rt - 4; 461233409Sgonzo if (args) 462233409Sgonzo args[arg] = kdbpeekd((int *)addr); 463233409Sgonzo if (valid_args) 464233409Sgonzo valid_args[arg] = 1; 465233409Sgonzo break; 466233409Sgonzo 467233409Sgonzo case 31: /* ra */ 468233409Sgonzo ra = kdbpeekd((int *)addr); 469233409Sgonzo } 470233409Sgonzo break; 471233409Sgonzo 472233409Sgonzo case OP_ADDI: 473233409Sgonzo case OP_ADDIU: 474233409Sgonzo case OP_DADDI: 475233409Sgonzo case OP_DADDIU: 476233409Sgonzo /* look for stack pointer adjustment */ 477233409Sgonzo if (i.IType.rs != 29 || i.IType.rt != 29) 478233409Sgonzo break; 479233409Sgonzo stksize = -((short)i.IType.imm); 480233409Sgonzo } 481233409Sgonzo } 482233409Sgonzo 483233409Sgonzo if (!MIPS_IS_VALID_KERNELADDR(ra)) 484233409Sgonzo return (-1); 485233409Sgonzo 486233409Sgonzo *pc = ra; 487233409Sgonzo *sp += stksize; 488233409Sgonzo 489233525Sgonzo#if defined(__mips_o32) 490233525Sgonzo /* 491233525Sgonzo * For MIPS32 fill out arguments 5..8 from the stack 492233525Sgonzo */ 493233525Sgonzo for (arg = 4; arg < 8; arg++) { 494233525Sgonzo addr = (vm_offset_t)(*sp + arg*sizeof(register_t)); 495233525Sgonzo if (args) 496233525Sgonzo args[arg] = kdbpeekd((int *)addr); 497233525Sgonzo if (valid_args) 498233525Sgonzo valid_args[arg] = 1; 499233525Sgonzo } 500233525Sgonzo#endif 501233525Sgonzo 502233409Sgonzo return (0); 503233409Sgonzoerror: 504233409Sgonzo return (-1); 505233409Sgonzo} 506233409Sgonzo 507233409Sgonzostatic int 508233409Sgonzodtrace_next_uframe(register_t *pc, register_t *sp, register_t *ra) 509233409Sgonzo{ 510233409Sgonzo int offset, registers_on_stack; 511233409Sgonzo uint32_t opcode, mask; 512233409Sgonzo register_t function_start; 513233409Sgonzo int stksize; 514233409Sgonzo InstFmt i; 515233409Sgonzo 516233525Sgonzo volatile uint16_t *flags = 517233525Sgonzo (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 518233525Sgonzo 519233409Sgonzo registers_on_stack = 0; 520233409Sgonzo mask = 0; 521233409Sgonzo function_start = 0; 522233409Sgonzo offset = 0; 523233409Sgonzo stksize = 0; 524233409Sgonzo 525233409Sgonzo while (offset < MAX_FUNCTION_SIZE) { 526233409Sgonzo opcode = dtrace_fuword32((void *)(vm_offset_t)(*pc - offset)); 527233409Sgonzo 528233525Sgonzo if (*flags & CPU_DTRACE_FAULT) 529233525Sgonzo goto fault; 530233525Sgonzo 531233409Sgonzo /* [d]addiu sp, sp, -X*/ 532233409Sgonzo if (((opcode & 0xffff8000) == 0x27bd8000) 533233409Sgonzo || ((opcode & 0xffff8000) == 0x67bd8000)) { 534233409Sgonzo function_start = *pc - offset; 535233409Sgonzo registers_on_stack = 1; 536233409Sgonzo break; 537233409Sgonzo } 538233409Sgonzo 539233409Sgonzo /* lui gp, X */ 540233409Sgonzo if ((opcode & 0xffff8000) == 0x3c1c0000) { 541233409Sgonzo /* 542233409Sgonzo * Function might start with this instruction 543233409Sgonzo * Keep an eye on "jr ra" and sp correction 544233409Sgonzo * with positive value further on 545233409Sgonzo */ 546233409Sgonzo function_start = *pc - offset; 547233409Sgonzo } 548233409Sgonzo 549233409Sgonzo if (function_start) { 550233409Sgonzo /* 551233409Sgonzo * Stop looking further. Possible end of 552233409Sgonzo * function instruction: it means there is no 553233409Sgonzo * stack modifications, sp is unchanged 554233409Sgonzo */ 555233409Sgonzo 556233409Sgonzo /* [d]addiu sp,sp,X */ 557233409Sgonzo if (((opcode & 0xffff8000) == 0x27bd0000) 558233409Sgonzo || ((opcode & 0xffff8000) == 0x67bd0000)) 559233409Sgonzo break; 560233409Sgonzo 561233409Sgonzo if (opcode == 0x03e00008) 562233409Sgonzo break; 563233409Sgonzo } 564233409Sgonzo 565233409Sgonzo offset += sizeof(int); 566233409Sgonzo } 567233409Sgonzo 568233409Sgonzo if (!function_start) 569233409Sgonzo return (-1); 570233409Sgonzo 571233409Sgonzo if (registers_on_stack) { 572233409Sgonzo offset = 0; 573233409Sgonzo while ((offset < MAX_PROLOGUE_SIZE) 574233409Sgonzo && ((function_start + offset) < *pc)) { 575233409Sgonzo i.word = 576233409Sgonzo dtrace_fuword32((void *)(vm_offset_t)(function_start + offset)); 577233409Sgonzo switch (i.JType.op) { 578233409Sgonzo case OP_SW: 579233409Sgonzo /* look for saved registers on the stack */ 580233409Sgonzo if (i.IType.rs != 29) 581233409Sgonzo break; 582233409Sgonzo /* only restore the first one */ 583233409Sgonzo if (mask & (1 << i.IType.rt)) 584233409Sgonzo break; 585233409Sgonzo mask |= (1 << i.IType.rt); 586233409Sgonzo if (i.IType.rt == 31) 587233409Sgonzo *ra = dtrace_fuword32((void *)(vm_offset_t)(*sp + (short)i.IType.imm)); 588233409Sgonzo break; 589233409Sgonzo 590233409Sgonzo case OP_SD: 591233409Sgonzo /* look for saved registers on the stack */ 592233409Sgonzo if (i.IType.rs != 29) 593233409Sgonzo break; 594233409Sgonzo /* only restore the first one */ 595233409Sgonzo if (mask & (1 << i.IType.rt)) 596233409Sgonzo break; 597233409Sgonzo mask |= (1 << i.IType.rt); 598233409Sgonzo /* ra */ 599233409Sgonzo if (i.IType.rt == 31) 600233409Sgonzo *ra = dtrace_fuword64((void *)(vm_offset_t)(*sp + (short)i.IType.imm)); 601233409Sgonzo break; 602233409Sgonzo 603233409Sgonzo case OP_ADDI: 604233409Sgonzo case OP_ADDIU: 605233409Sgonzo case OP_DADDI: 606233409Sgonzo case OP_DADDIU: 607233409Sgonzo /* look for stack pointer adjustment */ 608233409Sgonzo if (i.IType.rs != 29 || i.IType.rt != 29) 609233409Sgonzo break; 610233409Sgonzo stksize = -((short)i.IType.imm); 611233409Sgonzo } 612233409Sgonzo 613233409Sgonzo offset += sizeof(int); 614233525Sgonzo 615233525Sgonzo if (*flags & CPU_DTRACE_FAULT) 616233525Sgonzo goto fault; 617233409Sgonzo } 618233409Sgonzo } 619233409Sgonzo 620233409Sgonzo /* 621233409Sgonzo * We reached the end of backtrace 622233409Sgonzo */ 623233409Sgonzo if (*pc == *ra) 624233409Sgonzo return (-1); 625233409Sgonzo 626233409Sgonzo *pc = *ra; 627233409Sgonzo *sp += stksize; 628233409Sgonzo 629233409Sgonzo return (0); 630233525Sgonzofault: 631233525Sgonzo /* 632233525Sgonzo * We just got lost in backtrace, no big deal 633233525Sgonzo */ 634233525Sgonzo *flags &= ~CPU_DTRACE_FAULT; 635233525Sgonzo return (-1); 636233409Sgonzo} 637233409Sgonzo 638233409Sgonzostatic int 639233409Sgonzodtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size) 640233409Sgonzo{ 641233409Sgonzo 642233409Sgonzo if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) { 643233409Sgonzo DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 644233409Sgonzo cpu_core[curcpu].cpuc_dtrace_illval = uaddr; 645233409Sgonzo return (0); 646233409Sgonzo } 647233409Sgonzo 648233409Sgonzo return (1); 649233409Sgonzo} 650233409Sgonzo 651233409Sgonzovoid 652233409Sgonzodtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size, 653233409Sgonzo volatile uint16_t *flags) 654233409Sgonzo{ 655233409Sgonzo if (dtrace_copycheck(uaddr, kaddr, size)) 656233409Sgonzo dtrace_copy(uaddr, kaddr, size); 657233409Sgonzo} 658233409Sgonzo 659233409Sgonzovoid 660233409Sgonzodtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size, 661233409Sgonzo volatile uint16_t *flags) 662233409Sgonzo{ 663233409Sgonzo if (dtrace_copycheck(uaddr, kaddr, size)) 664233409Sgonzo dtrace_copy(kaddr, uaddr, size); 665233409Sgonzo} 666233409Sgonzo 667233409Sgonzovoid 668233409Sgonzodtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, 669233409Sgonzo volatile uint16_t *flags) 670233409Sgonzo{ 671233409Sgonzo if (dtrace_copycheck(uaddr, kaddr, size)) 672233409Sgonzo dtrace_copystr(uaddr, kaddr, size, flags); 673233409Sgonzo} 674233409Sgonzo 675233409Sgonzovoid 676233409Sgonzodtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size, 677233409Sgonzo volatile uint16_t *flags) 678233409Sgonzo{ 679233409Sgonzo if (dtrace_copycheck(uaddr, kaddr, size)) 680233409Sgonzo dtrace_copystr(kaddr, uaddr, size, flags); 681233409Sgonzo} 682233409Sgonzo 683233409Sgonzouint8_t 684233409Sgonzodtrace_fuword8(void *uaddr) 685233409Sgonzo{ 686233409Sgonzo if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 687233409Sgonzo DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 688233409Sgonzo cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 689233409Sgonzo return (0); 690233409Sgonzo } 691233409Sgonzo return (dtrace_fuword8_nocheck(uaddr)); 692233409Sgonzo} 693233409Sgonzo 694233409Sgonzouint16_t 695233409Sgonzodtrace_fuword16(void *uaddr) 696233409Sgonzo{ 697233409Sgonzo if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 698233409Sgonzo DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 699233409Sgonzo cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 700233409Sgonzo return (0); 701233409Sgonzo } 702233409Sgonzo return (dtrace_fuword16_nocheck(uaddr)); 703233409Sgonzo} 704233409Sgonzo 705233409Sgonzouint32_t 706233409Sgonzodtrace_fuword32(void *uaddr) 707233409Sgonzo{ 708233409Sgonzo if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 709233409Sgonzo DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 710233409Sgonzo cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 711233409Sgonzo return (0); 712233409Sgonzo } 713233409Sgonzo return (dtrace_fuword32_nocheck(uaddr)); 714233409Sgonzo} 715233409Sgonzo 716233409Sgonzouint64_t 717233409Sgonzodtrace_fuword64(void *uaddr) 718233409Sgonzo{ 719233409Sgonzo if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 720233409Sgonzo DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 721233409Sgonzo cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 722233409Sgonzo return (0); 723233409Sgonzo } 724233409Sgonzo return (dtrace_fuword64_nocheck(uaddr)); 725233409Sgonzo} 726