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