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 /*
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include <stdlib.h>
28 #include <assert.h>
29 #include <errno.h>
30 #include <string.h>
31 #include <libgen.h>
32
33 #include <dt_impl.h>
34 #include <dt_pid.h>
35
36 #define OP(x) ((x) >> 30)
37 #define OP2(x) (((x) >> 22) & 0x07)
38 #define COND(x) (((x) >> 25) & 0x0f)
39 #define A(x) (((x) >> 29) & 0x01)
40
41 #define OP_BRANCH 0
42
43 #define OP2_BPcc 0x1
44 #define OP2_Bicc 0x2
45 #define OP2_BPr 0x3
46 #define OP2_FBPfcc 0x5
47 #define OP2_FBfcc 0x6
48
49 /*ARGSUSED*/
50 int
dt_pid_create_entry_probe(struct ps_prochandle * P,dtrace_hdl_t * dtp,fasttrap_probe_spec_t * ftp,const GElf_Sym * symp)51 dt_pid_create_entry_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
52 fasttrap_probe_spec_t *ftp, const GElf_Sym *symp)
53 {
54 ftp->ftps_type = DTFTP_ENTRY;
55 ftp->ftps_pc = (uintptr_t)symp->st_value;
56 ftp->ftps_size = (size_t)symp->st_size;
57 ftp->ftps_noffs = 1;
58 ftp->ftps_offs[0] = 0;
59
60 if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
61 dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
62 strerror(errno));
63 return (dt_set_errno(dtp, errno));
64 }
65
66 return (1);
67 }
68
69 int
dt_pid_create_return_probe(struct ps_prochandle * P,dtrace_hdl_t * dtp,fasttrap_probe_spec_t * ftp,const GElf_Sym * symp,uint64_t * stret)70 dt_pid_create_return_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
71 fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, uint64_t *stret)
72 {
73
74 uint32_t *text;
75 int i;
76 int srdepth = 0;
77
78 if ((text = malloc(symp->st_size + 4)) == NULL) {
79 dt_dprintf("mr sparkle: malloc() failed\n");
80 return (DT_PROC_ERR);
81 }
82
83 if (Pread(P, text, symp->st_size, symp->st_value) != symp->st_size) {
84 dt_dprintf("mr sparkle: Pread() failed\n");
85 free(text);
86 return (DT_PROC_ERR);
87 }
88
89 /*
90 * Leave a dummy instruction in the last slot to simplify edge
91 * conditions.
92 */
93 text[symp->st_size / 4] = 0;
94
95 ftp->ftps_type = DTFTP_RETURN;
96 ftp->ftps_pc = symp->st_value;
97 ftp->ftps_size = symp->st_size;
98 ftp->ftps_noffs = 0;
99
100 for (i = 0; i < symp->st_size / 4; i++) {
101 /*
102 * If we encounter an existing tracepoint, query the
103 * kernel to find out the instruction that was
104 * replaced at this spot.
105 */
106 while (text[i] == FASTTRAP_INSTR) {
107 fasttrap_instr_query_t instr;
108
109 instr.ftiq_pid = Pstatus(P)->pr_pid;
110 instr.ftiq_pc = symp->st_value + i * 4;
111
112 if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_GETINSTR,
113 &instr) != 0) {
114
115 if (errno == ESRCH || errno == ENOENT) {
116 if (Pread(P, &text[i], 4,
117 instr.ftiq_pc) != 4) {
118 dt_dprintf("mr sparkle: "
119 "Pread() failed\n");
120 free(text);
121 return (DT_PROC_ERR);
122 }
123 continue;
124 }
125
126 free(text);
127 dt_dprintf("mr sparkle: getinstr query "
128 "failed: %s\n", strerror(errno));
129 return (DT_PROC_ERR);
130 }
131
132 text[i] = instr.ftiq_instr;
133 break;
134 }
135
136 /* save */
137 if ((text[i] & 0xc1f80000) == 0x81e00000) {
138 srdepth++;
139 continue;
140 }
141
142 /* restore */
143 if ((text[i] & 0xc1f80000) == 0x81e80000) {
144 srdepth--;
145 continue;
146 }
147
148 if (srdepth > 0) {
149 /* ret */
150 if (text[i] == 0x81c7e008)
151 goto is_ret;
152
153 /* return */
154 if (text[i] == 0x81cfe008)
155 goto is_ret;
156
157 /* call or jmpl w/ restore in the slot */
158 if (((text[i] & 0xc0000000) == 0x40000000 ||
159 (text[i] & 0xc1f80000) == 0x81c00000) &&
160 (text[i + 1] & 0xc1f80000) == 0x81e80000)
161 goto is_ret;
162
163 /* call to one of the stret routines */
164 if ((text[i] & 0xc0000000) == 0x40000000) {
165 int32_t disp = text[i] << 2;
166 uint64_t dest = ftp->ftps_pc + i * 4 + disp;
167
168 dt_dprintf("dest = %llx\n", (u_longlong_t)dest);
169
170 if (dest == stret[0] || dest == stret[1] ||
171 dest == stret[2] || dest == stret[3])
172 goto is_ret;
173 }
174 } else {
175 /* external call */
176 if ((text[i] & 0xc0000000) == 0x40000000) {
177 int32_t dst = text[i] << 2;
178
179 dst += i * 4;
180
181 if ((uintptr_t)dst >= (uintptr_t)symp->st_size)
182 goto is_ret;
183 }
184
185 /* jmpl into %g0 -- this includes the retl pseudo op */
186 if ((text[i] & 0xfff80000) == 0x81c00000)
187 goto is_ret;
188
189 /* external branch -- possible return site */
190 if (OP(text[i]) == OP_BRANCH) {
191 int32_t dst;
192 int baa;
193
194 switch (OP2(text[i])) {
195 case OP2_BPcc:
196 dst = text[i] & 0x7ffff;
197 dst <<= 13;
198 dst >>= 11;
199
200 baa = COND(text[i]) == 8 && A(text[i]);
201 break;
202 case OP2_Bicc:
203 dst = text[i] & 0x3fffff;
204 dst <<= 10;
205 dst >>= 8;
206
207 baa = COND(text[i]) == 8 && A(text[i]);
208 break;
209 case OP2_BPr:
210 dst = (((text[i]) >> 6) & 0xc000) |
211 ((text[i]) & 0x3fff);
212 dst <<= 16;
213 dst >>= 14;
214
215 baa = 0;
216 break;
217 case OP2_FBPfcc:
218 dst = text[i] & 0x7ffff;
219 dst <<= 13;
220 dst >>= 11;
221
222 baa = COND(text[i]) == 8 && A(text[i]);
223 break;
224 case OP2_FBfcc:
225 dst = text[i] & 0x3fffff;
226 dst <<= 10;
227 dst >>= 8;
228
229 baa = COND(text[i]) == 8 && A(text[i]);
230 break;
231 default:
232 continue;
233 }
234
235 dst += i * 4;
236
237 /*
238 * Interpret branches outside of the function's
239 * bounds as potential return sites. If the
240 * branch is a ba,a don't skip the instruction
241 * in the delay slot.
242 */
243 if ((uintptr_t)dst >=
244 (uintptr_t)symp->st_size) {
245 if (baa)
246 goto is_ret_baa;
247 else
248 goto is_ret;
249 }
250 }
251 }
252
253 continue;
254 is_ret:
255 i++;
256 is_ret_baa:
257 dt_dprintf("return at offset %x\n", i * 4);
258 ftp->ftps_offs[ftp->ftps_noffs++] = i * 4;
259 }
260
261 free(text);
262 if (ftp->ftps_noffs > 0) {
263 if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
264 dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
265 strerror(errno));
266 return (dt_set_errno(dtp, errno));
267 }
268 }
269
270
271 return (ftp->ftps_noffs);
272 }
273
274 /*ARGSUSED*/
275 int
dt_pid_create_offset_probe(struct ps_prochandle * P,dtrace_hdl_t * dtp,fasttrap_probe_spec_t * ftp,const GElf_Sym * symp,ulong_t off)276 dt_pid_create_offset_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
277 fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, ulong_t off)
278 {
279 if (off & 0x3)
280 return (DT_PROC_ALIGN);
281
282 ftp->ftps_type = DTFTP_OFFSETS;
283 ftp->ftps_pc = (uintptr_t)symp->st_value;
284 ftp->ftps_size = (size_t)symp->st_size;
285 ftp->ftps_noffs = 1;
286 ftp->ftps_offs[0] = off;
287
288 if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
289 dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
290 strerror(errno));
291 return (dt_set_errno(dtp, errno));
292 }
293
294 return (1);
295 }
296
297 /*ARGSUSED*/
298 int
dt_pid_create_glob_offset_probes(struct ps_prochandle * P,dtrace_hdl_t * dtp,fasttrap_probe_spec_t * ftp,const GElf_Sym * symp,const char * pattern)299 dt_pid_create_glob_offset_probes(struct ps_prochandle *P, dtrace_hdl_t *dtp,
300 fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, const char *pattern)
301 {
302 ulong_t i;
303
304 ftp->ftps_type = DTFTP_OFFSETS;
305 ftp->ftps_pc = (uintptr_t)symp->st_value;
306 ftp->ftps_size = (size_t)symp->st_size;
307 ftp->ftps_noffs = 0;
308
309 /*
310 * If we're matching against everything, just iterate through each
311 * instruction in the function, otherwise look for matching offset
312 * names by constructing the string and comparing it against the
313 * pattern.
314 */
315 if (strcmp("*", pattern) == 0) {
316 for (i = 0; i < symp->st_size; i += 4) {
317 ftp->ftps_offs[ftp->ftps_noffs++] = i;
318 }
319 } else {
320 char name[sizeof (i) * 2 + 1];
321
322 for (i = 0; i < symp->st_size; i += 4) {
323 (void) sprintf(name, "%lx", i);
324 if (gmatch(name, pattern))
325 ftp->ftps_offs[ftp->ftps_noffs++] = i;
326 }
327 }
328
329 if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
330 dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
331 strerror(errno));
332 return (dt_set_errno(dtp, errno));
333 }
334
335 return (ftp->ftps_noffs);
336 }
337