7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25 #include <objc/objc-runtime.h>
26 #import <Foundation/Foundation.h>
27 #import <JavaNativeFoundation/JavaNativeFoundation.h>
28 #import <JavaRuntimeSupport/JavaRuntimeSupport.h>
29
30 #include <jni.h>
31
32 #import <mach/mach.h>
33 #import <mach/mach_types.h>
34 #import <sys/sysctl.h>
35 #import <stdio.h>
36 #import <string.h>
37 #import <stdarg.h>
38 #import <stdlib.h>
39 #import <strings.h>
40 #import <dlfcn.h>
41 #import <limits.h>
42 #import <errno.h>
43 #import <sys/types.h>
44 #import <sys/ptrace.h>
45 #include "libproc_impl.h"
46
47 #define UNSUPPORTED_ARCH "Unsupported architecture!"
48
243 CHECK_EXCEPTION_(0);
244 }
245 symbolName_cstr = (*env)->GetStringUTFChars(env, symbolName, &isCopy);
246 if ((*env)->ExceptionOccurred(env)) {
247 if (objectName_cstr != NULL) {
248 (*env)->ReleaseStringUTFChars(env, objectName, objectName_cstr);
249 }
250 return 0;
251 }
252
253 print_debug("look for %s \n", symbolName_cstr);
254 addr = (jlong) lookup_symbol(ph, objectName_cstr, symbolName_cstr);
255
256 if (objectName_cstr != NULL) {
257 (*env)->ReleaseStringUTFChars(env, objectName, objectName_cstr);
258 }
259 (*env)->ReleaseStringUTFChars(env, symbolName, symbolName_cstr);
260 return addr;
261 }
262
263 /*
264 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
265 * Method: lookupByName0
266 * Signature: (Ljava/lang/String;Ljava/lang/String;)J
267 */
268 JNIEXPORT jlong JNICALL
269 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByName0(
270 JNIEnv *env, jobject this_obj,
271 jstring objectName, jstring symbolName)
272 {
273 struct ps_prochandle* ph = get_proc_handle(env, this_obj);
274 if (ph != NULL && ph->core != NULL) {
275 return lookupByNameIncore(env, ph, this_obj, objectName, symbolName);
276 }
277
278 jlong address = 0;
279
280 JNF_COCOA_ENTER(env);
281 NSString *symbolNameString = JNFJavaToNSString(env, symbolName);
282
283 print_debug("lookupInProcess called for %s\n", [symbolNameString UTF8String]);
284
285 id symbolicator = getSymbolicator(env, this_obj);
286 if (symbolicator != nil) {
287 uint64_t (*dynamicCall)(id, SEL, NSString *) = (uint64_t (*)(id, SEL, NSString *))&objc_msgSend;
288 address = (jlong) dynamicCall(symbolicator, @selector(addressForSymbol:), symbolNameString);
289 }
290
291 print_debug("address of symbol %s = %llx\n", [symbolNameString UTF8String], address);
292 JNF_COCOA_EXIT(env);
293
294 return address;
295 }
296
297 /*
298 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
299 * Method: lookupByAddress0
300 * Signature: (J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;
301 */
302 JNIEXPORT jobject JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByAddress0
303 (JNIEnv *env, jobject this_obj, jlong addr) {
304 uintptr_t offset;
305 const char* sym = NULL;
306 jstring sym_string;
307
308 struct ps_prochandle* ph = get_proc_handle(env, this_obj);
309 if (ph != NULL && ph->core != NULL) {
310 sym = symbol_for_pc(ph, (uintptr_t) addr, &offset);
311 if (sym == NULL) return 0;
312 sym_string = (*env)->NewStringUTF(env, sym);
788 print_debug("reply msg from mach_exc_server: (msg->{bits = %#x, size = %u, "
789 "remote_port = %#x, local_port = %#x, reserved = 0x%x, id = 0x%x},)",
790 rep_msg.header.msgh_bits, rep_msg.header.msgh_size,
791 rep_msg.header.msgh_remote_port, rep_msg.header.msgh_local_port,
792 rep_msg.header.msgh_reserved, rep_msg.header.msgh_id);
793
794 return true;
795 }
796
797 /*
798 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
799 * Method: attach0
800 * Signature: (I)V
801 */
802 JNIEXPORT void JNICALL
803 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__I(
804 JNIEnv *env, jobject this_obj, jint jpid)
805 {
806 print_debug("attach0 called for jpid=%d\n", (int)jpid);
807
808 JNF_COCOA_ENTER(env);
809
810 kern_return_t result;
811 task_t gTask = 0;
812
813 result = task_for_pid(mach_task_self(), jpid, &gTask);
814 if (result != KERN_SUCCESS) {
815 print_error("attach: task_for_pid(%d) failed: '%s' (%d)\n", (int)jpid, mach_error_string(result), result);
816 THROW_NEW_DEBUGGER_EXCEPTION(
817 "Can't attach to the process. Could be caused by an incorrect pid or lack of privileges.");
818 }
819 putTask(env, this_obj, gTask);
820
821 // Allocate an exception port.
822 result = mach_port_allocate(mach_task_self(),
823 MACH_PORT_RIGHT_RECEIVE,
824 &tgt_exception_port);
825 if (result != KERN_SUCCESS) {
826 print_error("attach: mach_port_allocate() for tgt_exception_port failed: '%s' (%d)\n",
827 mach_error_string(result), result);
828 THROW_NEW_DEBUGGER_EXCEPTION(
902 THROW_NEW_DEBUGGER_EXCEPTION("Can't attach. Unable to suspend all the threads in the task.");
903 }
904
905 id symbolicator = nil;
906 id jrsSymbolicator = objc_lookUpClass("JRSSymbolicator");
907 if (jrsSymbolicator != nil) {
908 id (*dynamicCall)(id, SEL, pid_t) = (id (*)(id, SEL, pid_t))&objc_msgSend;
909 symbolicator = dynamicCall(jrsSymbolicator, @selector(symbolicatorForPid:), (pid_t)jpid);
910 }
911 if (symbolicator != nil) {
912 CFRetain(symbolicator); // pin symbolicator while in java heap
913 }
914
915 putSymbolicator(env, this_obj, symbolicator);
916 if (symbolicator == nil) {
917 mach_port_deallocate(mach_task_self(), gTask);
918 mach_port_deallocate(mach_task_self(), tgt_exception_port);
919 THROW_NEW_DEBUGGER_EXCEPTION("Can't attach symbolicator to the process");
920 }
921
922 JNF_COCOA_EXIT(env);
923 }
924
925 /** For core file,
926 called from Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2 */
927 static void fillLoadObjects(JNIEnv* env, jobject this_obj, struct ps_prochandle* ph) {
928 int n = 0, i = 0;
929
930 // add load objects
931 n = get_num_libs(ph);
932 for (i = 0; i < n; i++) {
933 uintptr_t base;
934 const char* name;
935 jobject loadObject;
936 jobject loadObjectList;
937 jstring nameString;
938
939 base = get_lib_base(ph, i);
940 name = get_lib_name(ph, i);
941 nameString = (*env)->NewStringUTF(env, name);
942 CHECK_EXCEPTION;
996 if (throw_exception) {
997 THROW_NEW_DEBUGGER_EXCEPTION("Cannot detach.");
998 }
999 }
1000
1001 /*
1002 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
1003 * Method: detach0
1004 * Signature: ()V
1005 */
1006 JNIEXPORT void JNICALL
1007 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_detach0(
1008 JNIEnv *env, jobject this_obj)
1009 {
1010 print_debug("detach0 called\n");
1011 struct ps_prochandle* ph = get_proc_handle(env, this_obj);
1012 if (ph != NULL && ph->core != NULL) {
1013 Prelease(ph);
1014 return;
1015 }
1016 JNF_COCOA_ENTER(env);
1017
1018 task_t gTask = getTask(env, this_obj);
1019 kern_return_t k_res = 0;
1020
1021 // Restore the pre-saved original exception ports registered with the target process
1022 for (uint32_t i = 0; i < exception_saved_state.saved_exception_types_count; ++i) {
1023 k_res = task_set_exception_ports(gTask,
1024 exception_saved_state.saved_masks[i],
1025 exception_saved_state.saved_ports[i],
1026 exception_saved_state.saved_behaviors[i],
1027 exception_saved_state.saved_flavors[i]);
1028 if (k_res != KERN_SUCCESS) {
1029 print_error("detach: task_set_exception_ports failed with %d while "
1030 "restoring the target exception ports.\n", k_res);
1031 detach_cleanup(gTask, env, this_obj, true);
1032 }
1033 }
1034
1035 // detach from the ptraced process causing it to resume execution
1036 int pid;
1047 detach_cleanup(gTask, env, this_obj, true);
1048 }
1049 }
1050
1051 // reply to the previous exception message
1052 k_res = mach_msg(&rep_msg.header,
1053 MACH_SEND_MSG| MACH_SEND_INTERRUPT,
1054 rep_msg.header.msgh_size,
1055 0,
1056 MACH_PORT_NULL,
1057 MACH_MSG_TIMEOUT_NONE,
1058 MACH_PORT_NULL);
1059 if (k_res != MACH_MSG_SUCCESS) {
1060 print_error("detach: mach_msg() for replying to pending exceptions failed: '%s' (%d)\n",
1061 mach_error_string(k_res), k_res);
1062 detach_cleanup(gTask, env, this_obj, true);
1063 }
1064
1065 detach_cleanup(gTask, env, this_obj, false);
1066
1067 JNF_COCOA_EXIT(env);
1068 }
|
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25 #include <objc/objc-runtime.h>
26 #import <Foundation/Foundation.h>
27
28 #include <jni.h>
29
30 #import <mach/mach.h>
31 #import <mach/mach_types.h>
32 #import <sys/sysctl.h>
33 #import <stdio.h>
34 #import <string.h>
35 #import <stdarg.h>
36 #import <stdlib.h>
37 #import <strings.h>
38 #import <dlfcn.h>
39 #import <limits.h>
40 #import <errno.h>
41 #import <sys/types.h>
42 #import <sys/ptrace.h>
43 #include "libproc_impl.h"
44
45 #define UNSUPPORTED_ARCH "Unsupported architecture!"
46
241 CHECK_EXCEPTION_(0);
242 }
243 symbolName_cstr = (*env)->GetStringUTFChars(env, symbolName, &isCopy);
244 if ((*env)->ExceptionOccurred(env)) {
245 if (objectName_cstr != NULL) {
246 (*env)->ReleaseStringUTFChars(env, objectName, objectName_cstr);
247 }
248 return 0;
249 }
250
251 print_debug("look for %s \n", symbolName_cstr);
252 addr = (jlong) lookup_symbol(ph, objectName_cstr, symbolName_cstr);
253
254 if (objectName_cstr != NULL) {
255 (*env)->ReleaseStringUTFChars(env, objectName, objectName_cstr);
256 }
257 (*env)->ReleaseStringUTFChars(env, symbolName, symbolName_cstr);
258 return addr;
259 }
260
261 /* Create a pool and initiate a try block to catch any exception */
262 #define JNI_COCOA_ENTER(env) \
263 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; \
264 @try {
265
266 /* Don't allow NSExceptions to escape to Java.
267 * If there is a Java exception that has been thrown that should escape.
268 * And ensure we drain the auto-release pool.
269 */
270 #define JNI_COCOA_EXIT(env) \
271 } \
272 @catch (NSException *e) { \
273 NSLog(@"%@", [e callStackSymbols]); \
274 } \
275 @finally { \
276 [pool drain]; \
277 };
278
279 static NSString* JavaStringToNSString(JNIEnv *env, jstring jstr) {
280
281 if (jstr == NULL) {
282 return NULL;
283 }
284 jsize len = (*env)->GetStringLength(env, jstr);
285 const jchar *chars = (*env)->GetStringChars(env, jstr, NULL);
286 if (chars == NULL) {
287 return NULL;
288 }
289 NSString *result = [NSString stringWithCharacters:(UniChar *)chars length:len];
290 (*env)->ReleaseStringChars(env, jstr, chars);
291 return result;
292 }
293
294 /*
295 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
296 * Method: lookupByName0
297 * Signature: (Ljava/lang/String;Ljava/lang/String;)J
298 */
299 JNIEXPORT jlong JNICALL
300 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByName0(
301 JNIEnv *env, jobject this_obj,
302 jstring objectName, jstring symbolName)
303 {
304 struct ps_prochandle* ph = get_proc_handle(env, this_obj);
305 if (ph != NULL && ph->core != NULL) {
306 return lookupByNameIncore(env, ph, this_obj, objectName, symbolName);
307 }
308
309 jlong address = 0;
310
311 JNI_COCOA_ENTER(env);
312
313 NSString *symbolNameString = JavaStringToNSString(env, symbolName);
314
315 print_debug("lookupInProcess called for %s\n", [symbolNameString UTF8String]);
316
317 id symbolicator = getSymbolicator(env, this_obj);
318 if (symbolicator != nil) {
319 uint64_t (*dynamicCall)(id, SEL, NSString *) = (uint64_t (*)(id, SEL, NSString *))&objc_msgSend;
320 address = (jlong) dynamicCall(symbolicator, @selector(addressForSymbol:), symbolNameString);
321 }
322
323 print_debug("address of symbol %s = %llx\n", [symbolNameString UTF8String], address);
324 JNI_COCOA_EXIT(env);
325
326 return address;
327 }
328
329 /*
330 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
331 * Method: lookupByAddress0
332 * Signature: (J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;
333 */
334 JNIEXPORT jobject JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_lookupByAddress0
335 (JNIEnv *env, jobject this_obj, jlong addr) {
336 uintptr_t offset;
337 const char* sym = NULL;
338 jstring sym_string;
339
340 struct ps_prochandle* ph = get_proc_handle(env, this_obj);
341 if (ph != NULL && ph->core != NULL) {
342 sym = symbol_for_pc(ph, (uintptr_t) addr, &offset);
343 if (sym == NULL) return 0;
344 sym_string = (*env)->NewStringUTF(env, sym);
820 print_debug("reply msg from mach_exc_server: (msg->{bits = %#x, size = %u, "
821 "remote_port = %#x, local_port = %#x, reserved = 0x%x, id = 0x%x},)",
822 rep_msg.header.msgh_bits, rep_msg.header.msgh_size,
823 rep_msg.header.msgh_remote_port, rep_msg.header.msgh_local_port,
824 rep_msg.header.msgh_reserved, rep_msg.header.msgh_id);
825
826 return true;
827 }
828
829 /*
830 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
831 * Method: attach0
832 * Signature: (I)V
833 */
834 JNIEXPORT void JNICALL
835 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__I(
836 JNIEnv *env, jobject this_obj, jint jpid)
837 {
838 print_debug("attach0 called for jpid=%d\n", (int)jpid);
839
840 JNI_COCOA_ENTER(env);
841
842 kern_return_t result;
843 task_t gTask = 0;
844
845 result = task_for_pid(mach_task_self(), jpid, &gTask);
846 if (result != KERN_SUCCESS) {
847 print_error("attach: task_for_pid(%d) failed: '%s' (%d)\n", (int)jpid, mach_error_string(result), result);
848 THROW_NEW_DEBUGGER_EXCEPTION(
849 "Can't attach to the process. Could be caused by an incorrect pid or lack of privileges.");
850 }
851 putTask(env, this_obj, gTask);
852
853 // Allocate an exception port.
854 result = mach_port_allocate(mach_task_self(),
855 MACH_PORT_RIGHT_RECEIVE,
856 &tgt_exception_port);
857 if (result != KERN_SUCCESS) {
858 print_error("attach: mach_port_allocate() for tgt_exception_port failed: '%s' (%d)\n",
859 mach_error_string(result), result);
860 THROW_NEW_DEBUGGER_EXCEPTION(
934 THROW_NEW_DEBUGGER_EXCEPTION("Can't attach. Unable to suspend all the threads in the task.");
935 }
936
937 id symbolicator = nil;
938 id jrsSymbolicator = objc_lookUpClass("JRSSymbolicator");
939 if (jrsSymbolicator != nil) {
940 id (*dynamicCall)(id, SEL, pid_t) = (id (*)(id, SEL, pid_t))&objc_msgSend;
941 symbolicator = dynamicCall(jrsSymbolicator, @selector(symbolicatorForPid:), (pid_t)jpid);
942 }
943 if (symbolicator != nil) {
944 CFRetain(symbolicator); // pin symbolicator while in java heap
945 }
946
947 putSymbolicator(env, this_obj, symbolicator);
948 if (symbolicator == nil) {
949 mach_port_deallocate(mach_task_self(), gTask);
950 mach_port_deallocate(mach_task_self(), tgt_exception_port);
951 THROW_NEW_DEBUGGER_EXCEPTION("Can't attach symbolicator to the process");
952 }
953
954 JNI_COCOA_EXIT(env);
955 }
956
957 /** For core file,
958 called from Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2 */
959 static void fillLoadObjects(JNIEnv* env, jobject this_obj, struct ps_prochandle* ph) {
960 int n = 0, i = 0;
961
962 // add load objects
963 n = get_num_libs(ph);
964 for (i = 0; i < n; i++) {
965 uintptr_t base;
966 const char* name;
967 jobject loadObject;
968 jobject loadObjectList;
969 jstring nameString;
970
971 base = get_lib_base(ph, i);
972 name = get_lib_name(ph, i);
973 nameString = (*env)->NewStringUTF(env, name);
974 CHECK_EXCEPTION;
1028 if (throw_exception) {
1029 THROW_NEW_DEBUGGER_EXCEPTION("Cannot detach.");
1030 }
1031 }
1032
1033 /*
1034 * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal
1035 * Method: detach0
1036 * Signature: ()V
1037 */
1038 JNIEXPORT void JNICALL
1039 Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_detach0(
1040 JNIEnv *env, jobject this_obj)
1041 {
1042 print_debug("detach0 called\n");
1043 struct ps_prochandle* ph = get_proc_handle(env, this_obj);
1044 if (ph != NULL && ph->core != NULL) {
1045 Prelease(ph);
1046 return;
1047 }
1048
1049 JNI_COCOA_ENTER(env);
1050
1051 task_t gTask = getTask(env, this_obj);
1052 kern_return_t k_res = 0;
1053
1054 // Restore the pre-saved original exception ports registered with the target process
1055 for (uint32_t i = 0; i < exception_saved_state.saved_exception_types_count; ++i) {
1056 k_res = task_set_exception_ports(gTask,
1057 exception_saved_state.saved_masks[i],
1058 exception_saved_state.saved_ports[i],
1059 exception_saved_state.saved_behaviors[i],
1060 exception_saved_state.saved_flavors[i]);
1061 if (k_res != KERN_SUCCESS) {
1062 print_error("detach: task_set_exception_ports failed with %d while "
1063 "restoring the target exception ports.\n", k_res);
1064 detach_cleanup(gTask, env, this_obj, true);
1065 }
1066 }
1067
1068 // detach from the ptraced process causing it to resume execution
1069 int pid;
1080 detach_cleanup(gTask, env, this_obj, true);
1081 }
1082 }
1083
1084 // reply to the previous exception message
1085 k_res = mach_msg(&rep_msg.header,
1086 MACH_SEND_MSG| MACH_SEND_INTERRUPT,
1087 rep_msg.header.msgh_size,
1088 0,
1089 MACH_PORT_NULL,
1090 MACH_MSG_TIMEOUT_NONE,
1091 MACH_PORT_NULL);
1092 if (k_res != MACH_MSG_SUCCESS) {
1093 print_error("detach: mach_msg() for replying to pending exceptions failed: '%s' (%d)\n",
1094 mach_error_string(k_res), k_res);
1095 detach_cleanup(gTask, env, this_obj, true);
1096 }
1097
1098 detach_cleanup(gTask, env, this_obj, false);
1099
1100 JNI_COCOA_EXIT(env);
1101 }
|