1fed1ca4bSRuslan Bukin /*
2fed1ca4bSRuslan Bukin * CDDL HEADER START
3fed1ca4bSRuslan Bukin *
4fed1ca4bSRuslan Bukin * The contents of this file are subject to the terms of the
5fed1ca4bSRuslan Bukin * Common Development and Distribution License (the "License").
6fed1ca4bSRuslan Bukin * You may not use this file except in compliance with the License.
7fed1ca4bSRuslan Bukin *
8fed1ca4bSRuslan Bukin * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fed1ca4bSRuslan Bukin * or http://www.opensolaris.org/os/licensing.
10fed1ca4bSRuslan Bukin * See the License for the specific language governing permissions
11fed1ca4bSRuslan Bukin * and limitations under the License.
12fed1ca4bSRuslan Bukin *
13fed1ca4bSRuslan Bukin * When distributing Covered Code, include this CDDL HEADER in each
14fed1ca4bSRuslan Bukin * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fed1ca4bSRuslan Bukin * If applicable, add the following below this CDDL HEADER, with the
16fed1ca4bSRuslan Bukin * fields enclosed by brackets "[]" replaced with your own identifying
17fed1ca4bSRuslan Bukin * information: Portions Copyright [yyyy] [name of copyright owner]
18fed1ca4bSRuslan Bukin *
19fed1ca4bSRuslan Bukin * CDDL HEADER END
20fed1ca4bSRuslan Bukin *
21fed1ca4bSRuslan Bukin * Portions Copyright 2006-2008 John Birrell jb@freebsd.org
22fed1ca4bSRuslan Bukin * Portions Copyright 2013 Justin Hibbits jhibbits@freebsd.org
23fed1ca4bSRuslan Bukin * Portions Copyright 2013 Howard Su howardsu@freebsd.org
24378a4956SRuslan Bukin * Portions Copyright 2016-2018 Ruslan Bukin <br@bsdpad.com>
25fed1ca4bSRuslan Bukin */
26fed1ca4bSRuslan Bukin
27fed1ca4bSRuslan Bukin /*
28fed1ca4bSRuslan Bukin * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
29fed1ca4bSRuslan Bukin * Use is subject to license terms.
30fed1ca4bSRuslan Bukin */
31fed1ca4bSRuslan Bukin
32fed1ca4bSRuslan Bukin #include <sys/param.h>
33fed1ca4bSRuslan Bukin
34fed1ca4bSRuslan Bukin #include <sys/dtrace.h>
35fed1ca4bSRuslan Bukin
36fed1ca4bSRuslan Bukin #include <machine/riscvreg.h>
37378a4956SRuslan Bukin #include <machine/encoding.h>
38fed1ca4bSRuslan Bukin
39fed1ca4bSRuslan Bukin #include "fbt.h"
40fed1ca4bSRuslan Bukin
41378a4956SRuslan Bukin #define FBT_C_PATCHVAL MATCH_C_EBREAK
42378a4956SRuslan Bukin #define FBT_PATCHVAL MATCH_EBREAK
4336a9ce87SMitchell Horne #define FBT_AFRAMES 5
44fed1ca4bSRuslan Bukin
45fed1ca4bSRuslan Bukin int
fbt_invop(uintptr_t addr,struct trapframe * frame,uintptr_t rval)46fed1ca4bSRuslan Bukin fbt_invop(uintptr_t addr, struct trapframe *frame, uintptr_t rval)
47fed1ca4bSRuslan Bukin {
48fed1ca4bSRuslan Bukin solaris_cpu_t *cpu;
49fed1ca4bSRuslan Bukin fbt_probe_t *fbt;
50fed1ca4bSRuslan Bukin
51fed1ca4bSRuslan Bukin cpu = &solaris_cpu[curcpu];
52fed1ca4bSRuslan Bukin fbt = fbt_probetab[FBT_ADDR2NDX(addr)];
53fed1ca4bSRuslan Bukin
54fed1ca4bSRuslan Bukin for (; fbt != NULL; fbt = fbt->fbtp_hashnext) {
55fed1ca4bSRuslan Bukin if ((uintptr_t)fbt->fbtp_patchpoint == addr) {
56cdfa49f2SMitchell Horne cpu->cpu_dtrace_caller = frame->tf_ra - INSN_SIZE;
57fed1ca4bSRuslan Bukin
58effd82caSKristof Provost if (fbt->fbtp_roffset == 0) {
59fed1ca4bSRuslan Bukin dtrace_probe(fbt->fbtp_id, frame->tf_a[0],
60fed1ca4bSRuslan Bukin frame->tf_a[1], frame->tf_a[2],
61fed1ca4bSRuslan Bukin frame->tf_a[3], frame->tf_a[4]);
62effd82caSKristof Provost } else {
63effd82caSKristof Provost dtrace_probe(fbt->fbtp_id, fbt->fbtp_roffset,
64effd82caSKristof Provost frame->tf_a[0], frame->tf_a[1], 0, 0);
65effd82caSKristof Provost }
66fed1ca4bSRuslan Bukin
67fed1ca4bSRuslan Bukin cpu->cpu_dtrace_caller = 0;
68fed1ca4bSRuslan Bukin return (fbt->fbtp_savedval);
69fed1ca4bSRuslan Bukin }
70fed1ca4bSRuslan Bukin }
71fed1ca4bSRuslan Bukin
72fed1ca4bSRuslan Bukin return (0);
73fed1ca4bSRuslan Bukin }
74fed1ca4bSRuslan Bukin
75fed1ca4bSRuslan Bukin void
fbt_patch_tracepoint(fbt_probe_t * fbt,fbt_patchval_t val)76fed1ca4bSRuslan Bukin fbt_patch_tracepoint(fbt_probe_t *fbt, fbt_patchval_t val)
77fed1ca4bSRuslan Bukin {
78fed1ca4bSRuslan Bukin
79378a4956SRuslan Bukin switch(fbt->fbtp_patchval) {
80378a4956SRuslan Bukin case FBT_C_PATCHVAL:
81378a4956SRuslan Bukin *(uint16_t *)fbt->fbtp_patchpoint = (uint16_t)val;
8273efa2fbSJohn Baldwin fence_i();
83378a4956SRuslan Bukin break;
84378a4956SRuslan Bukin case FBT_PATCHVAL:
85fed1ca4bSRuslan Bukin *fbt->fbtp_patchpoint = val;
8673efa2fbSJohn Baldwin fence_i();
87378a4956SRuslan Bukin break;
88378a4956SRuslan Bukin };
89378a4956SRuslan Bukin }
90378a4956SRuslan Bukin
91fed1ca4bSRuslan Bukin int
fbt_provide_module_function(linker_file_t lf,int symindx,linker_symval_t * symval,void * opaque)92fed1ca4bSRuslan Bukin fbt_provide_module_function(linker_file_t lf, int symindx,
93fed1ca4bSRuslan Bukin linker_symval_t *symval, void *opaque)
94fed1ca4bSRuslan Bukin {
95fed1ca4bSRuslan Bukin fbt_probe_t *fbt, *retfbt;
96fed1ca4bSRuslan Bukin uint32_t *instr, *limit;
97fed1ca4bSRuslan Bukin const char *name;
98fed1ca4bSRuslan Bukin char *modname;
99378a4956SRuslan Bukin int patchval;
100378a4956SRuslan Bukin int rval;
101fed1ca4bSRuslan Bukin
102fed1ca4bSRuslan Bukin modname = opaque;
103fed1ca4bSRuslan Bukin name = symval->name;
104fed1ca4bSRuslan Bukin
105fed1ca4bSRuslan Bukin /* Check if function is excluded from instrumentation */
106fed1ca4bSRuslan Bukin if (fbt_excluded(name))
107fed1ca4bSRuslan Bukin return (0);
108fed1ca4bSRuslan Bukin
109f7439765SKristof Provost /*
110f7439765SKristof Provost * Some assembly-language exception handlers are not suitable for
111f7439765SKristof Provost * instrumentation.
112f7439765SKristof Provost */
113f7439765SKristof Provost if (strcmp(name, "cpu_exception_handler") == 0)
114f7439765SKristof Provost return (0);
115f7439765SKristof Provost if (strcmp(name, "cpu_exception_handler_user") == 0)
116f7439765SKristof Provost return (0);
117f7439765SKristof Provost if (strcmp(name, "cpu_exception_handler_supervisor") == 0)
118f7439765SKristof Provost return (0);
119f7439765SKristof Provost if (strcmp(name, "do_trap_supervisor") == 0)
120f7439765SKristof Provost return (0);
121f7439765SKristof Provost
122fed1ca4bSRuslan Bukin instr = (uint32_t *)(symval->value);
123fed1ca4bSRuslan Bukin limit = (uint32_t *)(symval->value + symval->size);
124fed1ca4bSRuslan Bukin
125fed1ca4bSRuslan Bukin /* Look for sd operation */
126fed1ca4bSRuslan Bukin for (; instr < limit; instr++) {
127378a4956SRuslan Bukin /* Look for a non-compressed store of ra to sp */
128*7a8cf053SChristos Margiolis if (dtrace_instr_sdsp(&instr)) {
129378a4956SRuslan Bukin rval = DTRACE_INVOP_SD;
130378a4956SRuslan Bukin patchval = FBT_PATCHVAL;
131fed1ca4bSRuslan Bukin break;
132fed1ca4bSRuslan Bukin }
133fed1ca4bSRuslan Bukin
134378a4956SRuslan Bukin /* Look for a 'C'-compressed store of ra to sp. */
135*7a8cf053SChristos Margiolis if (dtrace_instr_c_sdsp(&instr)) {
136378a4956SRuslan Bukin rval = DTRACE_INVOP_C_SDSP;
137378a4956SRuslan Bukin patchval = FBT_C_PATCHVAL;
138378a4956SRuslan Bukin break;
139378a4956SRuslan Bukin }
140378a4956SRuslan Bukin }
141378a4956SRuslan Bukin
142fed1ca4bSRuslan Bukin if (instr >= limit)
143fed1ca4bSRuslan Bukin return (0);
144fed1ca4bSRuslan Bukin
145fed1ca4bSRuslan Bukin fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO);
146fed1ca4bSRuslan Bukin fbt->fbtp_name = name;
147fed1ca4bSRuslan Bukin fbt->fbtp_id = dtrace_probe_create(fbt_id, modname,
14836a9ce87SMitchell Horne name, FBT_ENTRY, FBT_AFRAMES, fbt);
149fed1ca4bSRuslan Bukin fbt->fbtp_patchpoint = instr;
150fed1ca4bSRuslan Bukin fbt->fbtp_ctl = lf;
151fed1ca4bSRuslan Bukin fbt->fbtp_loadcnt = lf->loadcnt;
152fed1ca4bSRuslan Bukin fbt->fbtp_savedval = *instr;
153378a4956SRuslan Bukin fbt->fbtp_patchval = patchval;
154378a4956SRuslan Bukin fbt->fbtp_rval = rval;
155fed1ca4bSRuslan Bukin fbt->fbtp_symindx = symindx;
156fed1ca4bSRuslan Bukin
157fed1ca4bSRuslan Bukin fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)];
158fed1ca4bSRuslan Bukin fbt_probetab[FBT_ADDR2NDX(instr)] = fbt;
159fed1ca4bSRuslan Bukin
160fed1ca4bSRuslan Bukin lf->fbt_nentries++;
161fed1ca4bSRuslan Bukin
162fed1ca4bSRuslan Bukin retfbt = NULL;
163fed1ca4bSRuslan Bukin again:
164fed1ca4bSRuslan Bukin for (; instr < limit; instr++) {
165378a4956SRuslan Bukin /* Look for non-compressed return */
166*7a8cf053SChristos Margiolis if (dtrace_instr_ret(&instr)) {
167378a4956SRuslan Bukin rval = DTRACE_INVOP_RET;
168378a4956SRuslan Bukin patchval = FBT_PATCHVAL;
169fed1ca4bSRuslan Bukin break;
170fed1ca4bSRuslan Bukin }
171fed1ca4bSRuslan Bukin
172378a4956SRuslan Bukin /* Look for 'C'-compressed return */
173*7a8cf053SChristos Margiolis if (dtrace_instr_c_ret(&instr)) {
174378a4956SRuslan Bukin rval = DTRACE_INVOP_C_RET;
175378a4956SRuslan Bukin patchval = FBT_C_PATCHVAL;
176378a4956SRuslan Bukin break;
177378a4956SRuslan Bukin }
178378a4956SRuslan Bukin }
179378a4956SRuslan Bukin
180fed1ca4bSRuslan Bukin if (instr >= limit)
181fed1ca4bSRuslan Bukin return (0);
182fed1ca4bSRuslan Bukin
183fed1ca4bSRuslan Bukin /*
184fed1ca4bSRuslan Bukin * We have a winner!
185fed1ca4bSRuslan Bukin */
186fed1ca4bSRuslan Bukin fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO);
187fed1ca4bSRuslan Bukin fbt->fbtp_name = name;
188fed1ca4bSRuslan Bukin if (retfbt == NULL) {
189fed1ca4bSRuslan Bukin fbt->fbtp_id = dtrace_probe_create(fbt_id, modname,
19036a9ce87SMitchell Horne name, FBT_RETURN, FBT_AFRAMES, fbt);
191fed1ca4bSRuslan Bukin } else {
192c208cb99SMark Johnston retfbt->fbtp_probenext = fbt;
193fed1ca4bSRuslan Bukin fbt->fbtp_id = retfbt->fbtp_id;
194fed1ca4bSRuslan Bukin }
195fed1ca4bSRuslan Bukin retfbt = fbt;
196fed1ca4bSRuslan Bukin
197fed1ca4bSRuslan Bukin fbt->fbtp_patchpoint = instr;
198fed1ca4bSRuslan Bukin fbt->fbtp_ctl = lf;
199fed1ca4bSRuslan Bukin fbt->fbtp_loadcnt = lf->loadcnt;
200fed1ca4bSRuslan Bukin fbt->fbtp_symindx = symindx;
201378a4956SRuslan Bukin fbt->fbtp_rval = rval;
202effd82caSKristof Provost fbt->fbtp_roffset = (uintptr_t)instr - (uintptr_t)symval->value;
203fed1ca4bSRuslan Bukin fbt->fbtp_savedval = *instr;
204378a4956SRuslan Bukin fbt->fbtp_patchval = patchval;
205fed1ca4bSRuslan Bukin fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)];
206fed1ca4bSRuslan Bukin fbt_probetab[FBT_ADDR2NDX(instr)] = fbt;
207fed1ca4bSRuslan Bukin
208fed1ca4bSRuslan Bukin lf->fbt_nentries++;
209fed1ca4bSRuslan Bukin
210fed1ca4bSRuslan Bukin instr++;
211fed1ca4bSRuslan Bukin goto again;
212fed1ca4bSRuslan Bukin }
213