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 * Portions Copyright 2016 Ruslan Bukin <br@bsdpad.com> 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/encoding.h> 39 #include <machine/riscvreg.h> 40 41 #include <vm/vm.h> 42 #include <vm/vm_param.h> 43 #include <vm/pmap.h> 44 45 #include <machine/atomic.h> 46 #include <machine/db_machdep.h> 47 #include <machine/md_var.h> 48 #include <machine/stack.h> 49 #include <ddb/db_sym.h> 50 #include <ddb/ddb.h> 51 #include <sys/kdb.h> 52 53 #include "regset.h" 54 55 #define MAX_USTACK_DEPTH 2048 56 57 uint8_t dtrace_fuword8_nocheck(void *); 58 uint16_t dtrace_fuword16_nocheck(void *); 59 uint32_t dtrace_fuword32_nocheck(void *); 60 uint64_t dtrace_fuword64_nocheck(void *); 61 62 int dtrace_match_opcode(uint32_t, int, int); 63 int dtrace_instr_sdsp(uint32_t **); 64 int dtrace_instr_ret(uint32_t **); 65 int dtrace_instr_c_sdsp(uint32_t **); 66 int dtrace_instr_c_ret(uint32_t **); 67 68 void 69 dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, 70 uint32_t *intrpc) 71 { 72 struct unwind_state state; 73 uintptr_t caller; 74 register_t sp; 75 int scp_offset; 76 int depth; 77 78 depth = 0; 79 caller = solaris_cpu[curcpu].cpu_dtrace_caller; 80 81 if (intrpc != 0) { 82 pcstack[depth++] = (pc_t)intrpc; 83 } 84 85 /* 86 * Construct the unwind state, starting from this function. This frame, 87 * and 'aframes' others will be skipped. 88 */ 89 __asm __volatile("mv %0, sp" : "=&r" (sp)); 90 91 state.fp = (uintptr_t)__builtin_frame_address(0); 92 state.sp = (uintptr_t)sp; 93 state.pc = (uintptr_t)dtrace_getpcstack; 94 95 while (depth < pcstack_limit) { 96 if (!unwind_frame(curthread, &state)) 97 break; 98 99 if (!INKERNEL(state.pc) || !kstack_contains(curthread, 100 (vm_offset_t)state.fp, sizeof(uintptr_t))) 101 break; 102 103 if (aframes > 0) { 104 aframes--; 105 106 /* 107 * fbt_invop() records the return address at the time 108 * the FBT probe fires. We need to insert this into the 109 * backtrace manually, since the stack frame state at 110 * the time of the probe does not capture it. 111 */ 112 if (aframes == 0 && caller != 0) 113 pcstack[depth++] = caller; 114 } else { 115 pcstack[depth++] = state.pc; 116 } 117 } 118 119 for (; depth < pcstack_limit; depth++) { 120 pcstack[depth] = 0; 121 } 122 } 123 124 static int 125 dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc, 126 uintptr_t fp) 127 { 128 volatile uint16_t *flags; 129 uintptr_t oldfp; 130 int ret; 131 132 oldfp = fp; 133 ret = 0; 134 flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 135 136 ASSERT(pcstack == NULL || pcstack_limit > 0); 137 138 while (pc != 0) { 139 /* 140 * We limit the number of times we can go around this 141 * loop to account for a circular stack. 142 */ 143 if (ret++ >= MAX_USTACK_DEPTH) { 144 *flags |= CPU_DTRACE_BADSTACK; 145 cpu_core[curcpu].cpuc_dtrace_illval = fp; 146 break; 147 } 148 149 if (pcstack != NULL) { 150 *pcstack++ = (uint64_t)pc; 151 pcstack_limit--; 152 if (pcstack_limit <= 0) 153 break; 154 } 155 156 if (fp == 0) 157 break; 158 159 pc = dtrace_fuword64((void *)(fp - 1 * sizeof(uint64_t))); 160 fp = dtrace_fuword64((void *)(fp - 2 * sizeof(uint64_t))); 161 162 if (fp == oldfp) { 163 *flags |= CPU_DTRACE_BADSTACK; 164 cpu_core[curcpu].cpuc_dtrace_illval = fp; 165 break; 166 } 167 oldfp = fp; 168 } 169 170 return (ret); 171 } 172 173 void 174 dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) 175 { 176 volatile uint16_t *flags; 177 struct trapframe *tf; 178 uintptr_t pc, fp; 179 proc_t *p; 180 int n; 181 182 p = curproc; 183 flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 184 185 if (*flags & CPU_DTRACE_FAULT) 186 return; 187 188 if (pcstack_limit <= 0) 189 return; 190 191 /* 192 * If there's no user context we still need to zero the stack. 193 */ 194 if (p == NULL || (tf = curthread->td_frame) == NULL) 195 goto zero; 196 197 *pcstack++ = (uint64_t)p->p_pid; 198 pcstack_limit--; 199 200 if (pcstack_limit <= 0) 201 return; 202 203 pc = tf->tf_sepc; 204 fp = tf->tf_s[0]; 205 206 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 207 /* 208 * In an entry probe. The frame pointer has not yet been 209 * pushed (that happens in the function prologue). The 210 * best approach is to add the current pc as a missing top 211 * of stack and back the pc up to the caller, which is stored 212 * at the current stack pointer address since the call 213 * instruction puts it there right before the branch. 214 */ 215 *pcstack++ = (uint64_t)pc; 216 pcstack_limit--; 217 if (pcstack_limit <= 0) 218 return; 219 220 pc = tf->tf_ra; 221 } 222 223 n = dtrace_getustack_common(pcstack, pcstack_limit, pc, fp); 224 ASSERT(n >= 0); 225 ASSERT(n <= pcstack_limit); 226 227 pcstack += n; 228 pcstack_limit -= n; 229 230 zero: 231 while (pcstack_limit-- > 0) 232 *pcstack++ = 0; 233 } 234 235 int 236 dtrace_getustackdepth(void) 237 { 238 struct trapframe *tf; 239 uintptr_t pc, fp; 240 int n = 0; 241 242 if (curproc == NULL || (tf = curthread->td_frame) == NULL) 243 return (0); 244 245 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT)) 246 return (-1); 247 248 pc = tf->tf_sepc; 249 fp = tf->tf_s[0]; 250 251 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 252 /* 253 * In an entry probe. The frame pointer has not yet been 254 * pushed (that happens in the function prologue). The 255 * best approach is to add the current pc as a missing top 256 * of stack and back the pc up to the caller, which is stored 257 * at the current stack pointer address since the call 258 * instruction puts it there right before the branch. 259 */ 260 pc = tf->tf_ra; 261 n++; 262 } 263 264 n += dtrace_getustack_common(NULL, 0, pc, fp); 265 266 return (0); 267 } 268 269 void 270 dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) 271 { 272 273 printf("IMPLEMENT ME: %s\n", __func__); 274 } 275 276 /*ARGSUSED*/ 277 uint64_t 278 dtrace_getarg(int arg, int aframes) 279 { 280 281 printf("IMPLEMENT ME: %s\n", __func__); 282 283 return (0); 284 } 285 286 int 287 dtrace_getstackdepth(int aframes) 288 { 289 struct unwind_state state; 290 int scp_offset; 291 register_t sp; 292 int depth; 293 bool done; 294 295 depth = 1; 296 done = false; 297 298 __asm __volatile("mv %0, sp" : "=&r" (sp)); 299 300 state.fp = (uintptr_t)__builtin_frame_address(0); 301 state.sp = sp; 302 state.pc = (uintptr_t)dtrace_getstackdepth; 303 304 do { 305 done = !unwind_frame(curthread, &state); 306 if (!INKERNEL(state.pc) || !INKERNEL(state.fp)) 307 break; 308 depth++; 309 } while (!done); 310 311 if (depth < aframes) 312 return (0); 313 else 314 return (depth - aframes); 315 } 316 317 ulong_t 318 dtrace_getreg(struct trapframe *frame, uint_t reg) 319 { 320 switch (reg) { 321 case REG_ZERO: 322 return (0); 323 case REG_RA: 324 return (frame->tf_ra); 325 case REG_SP: 326 return (frame->tf_sp); 327 case REG_GP: 328 return (frame->tf_gp); 329 case REG_TP: 330 return (frame->tf_tp); 331 case REG_T0 ... REG_T2: 332 return (frame->tf_t[reg - REG_T0]); 333 case REG_S0 ... REG_S1: 334 return (frame->tf_s[reg - REG_S0]); 335 case REG_A0 ... REG_A7: 336 return (frame->tf_a[reg - REG_A0]); 337 case REG_S2 ... REG_S11: 338 return (frame->tf_s[reg - REG_S2 + 2]); 339 case REG_T3 ... REG_T6: 340 return (frame->tf_t[reg - REG_T3 + 3]); 341 case REG_PC: 342 return (frame->tf_sepc); 343 default: 344 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); 345 return (0); 346 } 347 /* NOTREACHED */ 348 } 349 350 static int 351 dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size) 352 { 353 354 if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) { 355 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 356 cpu_core[curcpu].cpuc_dtrace_illval = uaddr; 357 return (0); 358 } 359 360 return (1); 361 } 362 363 void 364 dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size, 365 volatile uint16_t *flags) 366 { 367 368 if (dtrace_copycheck(uaddr, kaddr, size)) 369 dtrace_copy(uaddr, kaddr, size); 370 } 371 372 void 373 dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size, 374 volatile uint16_t *flags) 375 { 376 377 if (dtrace_copycheck(uaddr, kaddr, size)) 378 dtrace_copy(kaddr, uaddr, size); 379 } 380 381 void 382 dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, 383 volatile uint16_t *flags) 384 { 385 386 if (dtrace_copycheck(uaddr, kaddr, size)) 387 dtrace_copystr(uaddr, kaddr, size, flags); 388 } 389 390 void 391 dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size, 392 volatile uint16_t *flags) 393 { 394 395 if (dtrace_copycheck(uaddr, kaddr, size)) 396 dtrace_copystr(kaddr, uaddr, size, flags); 397 } 398 399 uint8_t 400 dtrace_fuword8(void *uaddr) 401 { 402 403 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 404 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 405 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 406 return (0); 407 } 408 409 return (dtrace_fuword8_nocheck(uaddr)); 410 } 411 412 uint16_t 413 dtrace_fuword16(void *uaddr) 414 { 415 416 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 417 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 418 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 419 return (0); 420 } 421 422 return (dtrace_fuword16_nocheck(uaddr)); 423 } 424 425 uint32_t 426 dtrace_fuword32(void *uaddr) 427 { 428 429 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 430 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 431 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 432 return (0); 433 } 434 435 return (dtrace_fuword32_nocheck(uaddr)); 436 } 437 438 uint64_t 439 dtrace_fuword64(void *uaddr) 440 { 441 442 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 443 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 444 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 445 return (0); 446 } 447 448 return (dtrace_fuword64_nocheck(uaddr)); 449 } 450 451 int 452 dtrace_match_opcode(uint32_t insn, int match, int mask) 453 { 454 if (((insn ^ match) & mask) == 0) 455 return (1); 456 457 return (0); 458 } 459 460 int 461 dtrace_instr_sdsp(uint32_t **instr) 462 { 463 if (dtrace_match_opcode(**instr, (MATCH_SD | RS2_RA | RS1_SP), 464 (MASK_SD | RS2_MASK | RS1_MASK))) 465 return (1); 466 467 return (0); 468 } 469 470 int 471 dtrace_instr_c_sdsp(uint32_t **instr) 472 { 473 uint16_t *instr1; 474 int i; 475 476 for (i = 0; i < 2; i++) { 477 instr1 = (uint16_t *)(*instr) + i; 478 if (dtrace_match_opcode(*instr1, (MATCH_C_SDSP | RS2_C_RA), 479 (MASK_C_SDSP | RS2_C_MASK))) { 480 *instr = (uint32_t *)instr1; 481 return (1); 482 } 483 } 484 485 return (0); 486 } 487 488 int 489 dtrace_instr_ret(uint32_t **instr) 490 { 491 if (dtrace_match_opcode(**instr, (MATCH_JALR | (X_RA << RS1_SHIFT)), 492 (MASK_JALR | RD_MASK | RS1_MASK | IMM_MASK))) 493 return (1); 494 495 return (0); 496 } 497 498 int 499 dtrace_instr_c_ret(uint32_t **instr) 500 { 501 uint16_t *instr1; 502 int i; 503 504 for (i = 0; i < 2; i++) { 505 instr1 = (uint16_t *)(*instr) + i; 506 if (dtrace_match_opcode(*instr1, 507 (MATCH_C_JR | (X_RA << RD_SHIFT)), (MASK_C_JR | RD_MASK))) { 508 *instr = (uint32_t *)instr1; 509 return (1); 510 } 511 } 512 513 return (0); 514 } 515