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