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