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 * $FreeBSD$ 25 */ 26 /* 27 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 #include <sys/cdefs.h> 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/kernel.h> 35 #include <sys/stack.h> 36 #include <sys/pcpu.h> 37 38 #include <machine/frame.h> 39 #include <machine/md_var.h> 40 #include <machine/reg.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 /* 57 * Wee need some reasonable default to prevent backtrace code 58 * from wandering too far 59 */ 60 #define MAX_FUNCTION_SIZE 0x10000 61 #define MAX_PROLOGUE_SIZE 0x100 62 #define MAX_USTACK_DEPTH 2048 63 64 uint8_t dtrace_fuword8_nocheck(void *); 65 uint16_t dtrace_fuword16_nocheck(void *); 66 uint32_t dtrace_fuword32_nocheck(void *); 67 uint64_t dtrace_fuword64_nocheck(void *); 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 int scp_offset; 75 register_t sp; 76 int depth; 77 78 depth = 0; 79 80 if (intrpc != 0) { 81 pcstack[depth++] = (pc_t) intrpc; 82 } 83 84 aframes++; 85 86 __asm __volatile("mv %0, sp" : "=&r" (sp)); 87 88 state.fp = (uintptr_t)__builtin_frame_address(0); 89 state.sp = sp; 90 state.pc = (uintptr_t)dtrace_getpcstack; 91 92 while (depth < pcstack_limit) { 93 if (!unwind_frame(curthread, &state)) 94 break; 95 96 if (!INKERNEL(state.pc) || !INKERNEL(state.fp)) 97 break; 98 99 /* 100 * NB: Unlike some other architectures, we don't need to 101 * explicitly insert cpu_dtrace_caller as it appears in the 102 * normal kernel stack trace rather than a special trap frame. 103 */ 104 if (aframes > 0) { 105 aframes--; 106 } else { 107 pcstack[depth++] = state.pc; 108 } 109 110 } 111 112 for (; depth < pcstack_limit; depth++) { 113 pcstack[depth] = 0; 114 } 115 } 116 117 static int 118 dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc, 119 uintptr_t fp) 120 { 121 volatile uint16_t *flags; 122 uintptr_t oldfp; 123 int ret; 124 125 oldfp = fp; 126 ret = 0; 127 flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 128 129 ASSERT(pcstack == NULL || pcstack_limit > 0); 130 131 while (pc != 0) { 132 /* 133 * We limit the number of times we can go around this 134 * loop to account for a circular stack. 135 */ 136 if (ret++ >= MAX_USTACK_DEPTH) { 137 *flags |= CPU_DTRACE_BADSTACK; 138 cpu_core[curcpu].cpuc_dtrace_illval = fp; 139 break; 140 } 141 142 if (pcstack != NULL) { 143 *pcstack++ = (uint64_t)pc; 144 pcstack_limit--; 145 if (pcstack_limit <= 0) 146 break; 147 } 148 149 if (fp == 0) 150 break; 151 152 pc = dtrace_fuword64((void *)(fp + 153 offsetof(struct riscv_frame, f_retaddr))); 154 fp = dtrace_fuword64((void *)fp); 155 156 if (fp == oldfp) { 157 *flags |= CPU_DTRACE_BADSTACK; 158 cpu_core[curcpu].cpuc_dtrace_illval = fp; 159 break; 160 } 161 oldfp = fp; 162 } 163 164 return (ret); 165 } 166 167 void 168 dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) 169 { 170 volatile uint16_t *flags; 171 struct trapframe *tf; 172 uintptr_t pc, sp, fp; 173 proc_t *p; 174 int n; 175 176 p = curproc; 177 flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 178 179 if (*flags & CPU_DTRACE_FAULT) 180 return; 181 182 if (pcstack_limit <= 0) 183 return; 184 185 /* 186 * If there's no user context we still need to zero the stack. 187 */ 188 if (p == NULL || (tf = curthread->td_frame) == NULL) 189 goto zero; 190 191 *pcstack++ = (uint64_t)p->p_pid; 192 pcstack_limit--; 193 194 if (pcstack_limit <= 0) 195 return; 196 197 pc = tf->tf_sepc; 198 sp = tf->tf_sp; 199 fp = tf->tf_s[0]; 200 201 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 202 /* 203 * In an entry probe. The frame pointer has not yet been 204 * pushed (that happens in the function prologue). The 205 * best approach is to add the current pc as a missing top 206 * of stack and back the pc up to the caller, which is stored 207 * at the current stack pointer address since the call 208 * instruction puts it there right before the branch. 209 */ 210 211 *pcstack++ = (uint64_t)pc; 212 pcstack_limit--; 213 if (pcstack_limit <= 0) 214 return; 215 216 pc = tf->tf_ra; 217 } 218 219 n = dtrace_getustack_common(pcstack, pcstack_limit, pc, fp); 220 ASSERT(n >= 0); 221 ASSERT(n <= pcstack_limit); 222 223 pcstack += n; 224 pcstack_limit -= n; 225 226 zero: 227 while (pcstack_limit-- > 0) 228 *pcstack++ = 0; 229 } 230 231 int 232 dtrace_getustackdepth(void) 233 { 234 235 printf("IMPLEMENT ME: %s\n", __func__); 236 237 return (0); 238 } 239 240 void 241 dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) 242 { 243 244 printf("IMPLEMENT ME: %s\n", __func__); 245 } 246 247 /*ARGSUSED*/ 248 uint64_t 249 dtrace_getarg(int arg, int aframes) 250 { 251 252 printf("IMPLEMENT ME: %s\n", __func__); 253 254 return (0); 255 } 256 257 int 258 dtrace_getstackdepth(int aframes) 259 { 260 struct unwind_state state; 261 int scp_offset; 262 register_t sp; 263 int depth; 264 bool done; 265 266 depth = 1; 267 done = false; 268 269 __asm __volatile("mv %0, sp" : "=&r" (sp)); 270 271 state.fp = (uintptr_t)__builtin_frame_address(0); 272 state.sp = sp; 273 state.pc = (uintptr_t)dtrace_getstackdepth; 274 275 do { 276 done = !unwind_frame(curthread, &state); 277 if (!INKERNEL(state.pc) || !INKERNEL(state.fp)) 278 break; 279 depth++; 280 } while (!done); 281 282 if (depth < aframes) 283 return (0); 284 else 285 return (depth - aframes); 286 } 287 288 ulong_t 289 dtrace_getreg(struct trapframe *rp, uint_t reg) 290 { 291 292 printf("IMPLEMENT ME: %s\n", __func__); 293 294 return (0); 295 } 296 297 static int 298 dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size) 299 { 300 301 if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) { 302 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 303 cpu_core[curcpu].cpuc_dtrace_illval = uaddr; 304 return (0); 305 } 306 307 return (1); 308 } 309 310 void 311 dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size, 312 volatile uint16_t *flags) 313 { 314 315 if (dtrace_copycheck(uaddr, kaddr, size)) 316 dtrace_copy(uaddr, kaddr, size); 317 } 318 319 void 320 dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size, 321 volatile uint16_t *flags) 322 { 323 324 if (dtrace_copycheck(uaddr, kaddr, size)) 325 dtrace_copy(kaddr, uaddr, size); 326 } 327 328 void 329 dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, 330 volatile uint16_t *flags) 331 { 332 333 if (dtrace_copycheck(uaddr, kaddr, size)) 334 dtrace_copystr(uaddr, kaddr, size, flags); 335 } 336 337 void 338 dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size, 339 volatile uint16_t *flags) 340 { 341 342 if (dtrace_copycheck(uaddr, kaddr, size)) 343 dtrace_copystr(kaddr, uaddr, size, flags); 344 } 345 346 uint8_t 347 dtrace_fuword8(void *uaddr) 348 { 349 350 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 351 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 352 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 353 return (0); 354 } 355 356 return (dtrace_fuword8_nocheck(uaddr)); 357 } 358 359 uint16_t 360 dtrace_fuword16(void *uaddr) 361 { 362 363 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 364 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 365 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 366 return (0); 367 } 368 369 return (dtrace_fuword16_nocheck(uaddr)); 370 } 371 372 uint32_t 373 dtrace_fuword32(void *uaddr) 374 { 375 376 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 377 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 378 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 379 return (0); 380 } 381 382 return (dtrace_fuword32_nocheck(uaddr)); 383 } 384 385 uint64_t 386 dtrace_fuword64(void *uaddr) 387 { 388 389 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 390 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 391 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 392 return (0); 393 } 394 395 return (dtrace_fuword64_nocheck(uaddr)); 396 } 397