1 #!/usr/sbin/dtrace -Zs
2 
3 /*
4  * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  *   - Redistributions of source code must retain the above copyright
11  *     notice, this list of conditions and the following disclaimer.
12  *
13  *   - Redistributions in binary form must reproduce the above copyright
14  *     notice, this list of conditions and the following disclaimer in the
15  *     documentation and/or other materials provided with the distribution.
16  *
17  *   - Neither the name of Oracle nor the names of its
18  *     contributors may be used to endorse or promote products derived
19  *     from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
22  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
25  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 /*
35 */
36 
37 /*
38  * Usage:
39  *    1. CriticalSection_slow.d -c "java ..."
40  *    2. CriticalSection_slow.d -p JAVA_PID
41  *
42  * The script inspect a JNI application for Critical Section violations.
43  *
44  * Critical section is the space between calls to JNI methods:
45  *   - GetPrimitiveArrayCritical and ReleasePrimitiveArrayCritical; or
46  *   - GetStringCritical and ReleaseStringCritical.
47  *
48  * Inside a critical section, native code must not call other JNI functions,
49  * or any system call that may cause the current thread to block and wait
50  * for another Java thread. (For example, the current thread must not call
51  * read on a stream being written by another Java thread.)
52  *
53  */
54 
55 #pragma D option quiet
56 #pragma D option destructive
57 #pragma D option defaultargs
58 #pragma D option bufsize=16m
59 #pragma D option aggrate=100ms
60 
61 
62 self int in_critical_section;
63 self string critical_section_name;
64 
65 self char *str_ptr;
66 self string class_name;
67 self string method_name;
68 self string signature;
69 
70 self int indent;
71 self int JAVA_STACK_DEEP;
72 
73 int CRITICAL_SECTION_VIOLATION_CNT;
74 
75 :::BEGIN
76 {
77     SAMPLE_NAME = "critical section violation checks";
78 
79     printf("BEGIN %s\n", SAMPLE_NAME);
80 }
81 
82 hotspot$target:::*
83 /!self->JAVA_STACK_DEEP/
84 {
85     self->JAVA_STACK_DEEP = 0;
86 }
87 
88 
89 hotspot$target:::method-return
90 /self->JAVA_STACK_DEEP > 0/
91 {
92     self->JAVA_STACK_DEEP --;
93 }
94 
95 hotspot$target:::method-entry
96 {
97     self->JAVA_STACK_DEEP ++;
98 
99     self->str_ptr = (char*) copyin(arg1, arg2+1);
100     self->str_ptr[arg2] = '\0';
101     self->method_name = strjoin( (string) self->str_ptr, ":");
102 
103     self->str_ptr = (char*) copyin(arg3, arg4+1);
104     self->str_ptr[arg4] = '\0';
105     self->method_name = strjoin(self->method_name, (string) self->str_ptr);
106     self->method_name = strjoin(self->method_name, ":");
107 
108     self->str_ptr = (char*) copyin(arg5, arg6+1);
109     self->str_ptr[arg6] = '\0';
110     self->method_name = strjoin(self->method_name, (string) self->str_ptr);
111 
112     self->JAVA_STACK[self->JAVA_STACK_DEEP] = self->method_name;
113 
114 /*    printf("%-10u%*s%s\n",
115  *      curcpu->cpu_id, self->indent, "", self->method_name);
116  */
117 }
118 
119 
120 /*
121  *   Multiple pairs of GetPrimitiveArrayCritical/ReleasePrimitiveArrayCritical,
122  *   GetStringCritical/ReleaseStringCritical may be nested
123  */
124 hotspot_jni$target:::*_entry
125 /self->in_critical_section > 0 &&
126   probename != "GetPrimitiveArrayCritical_entry" &&
127   probename != "GetStringCritical_entry" &&
128   probename != "ReleasePrimitiveArrayCritical_entry" &&
129   probename != "ReleaseStringCritical_entry" &&
130   probename != "GetPrimitiveArrayCritical_return" &&
131   probename != "GetStringCritical_return" &&
132   probename != "ReleasePrimitiveArrayCritical_return" &&
133   probename != "ReleaseStringCritical_return"/
134 {
135     printf("JNI call %s made from JNI critical region '%s' from %s\n",
136         probename, self->critical_section_name,
137         self->JAVA_STACK[self->JAVA_STACK_DEEP]);
138 
139     CRITICAL_SECTION_VIOLATION_CNT ++;
140 }
141 
142 syscall:::entry
143 /pid == $target && self->in_critical_section > 0/
144 {
145     printf("system call %s made in JNI critical region '%s' from %s\n",
146         probefunc, self->critical_section_name,
147         self->JAVA_STACK[self->JAVA_STACK_DEEP]);
148 
149     CRITICAL_SECTION_VIOLATION_CNT ++;
150 }
151 
152 hotspot_jni$target:::ReleasePrimitiveArrayCritical_entry,
153 hotspot_jni$target:::ReleaseStringCritical_entry
154 /self->in_critical_section > 0/
155 {
156     self->in_critical_section --;
157 }
158 
159 hotspot_jni$target:::GetPrimitiveArrayCritical_return
160 {
161     self->in_critical_section ++;
162     self->critical_section_name = "GetPrimitiveArrayCritical";
163 }
164 
165 hotspot_jni$target:::GetStringCritical_return
166 {
167     self->in_critical_section ++;
168     self->critical_section_name = "GetStringCritical";
169 }
170 
171 
172 :::END
173 {
174     printf("%d critical section violations have been discovered\n",
175         CRITICAL_SECTION_VIOLATION_CNT);
176 
177     printf("\nEND of %s\n", SAMPLE_NAME);
178 }
179