xref: /freebsd/sys/cddl/dev/fbt/riscv/fbt_isa.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
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