1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 /* 18 * dalvik.system.VMStack 19 */ 20 #include "Dalvik.h" 21 #include "native/InternalNativePriv.h" 22 23 24 /* 25 * public static ClassLoader getCallingClassLoader() 26 * 27 * Return the defining class loader of the caller's caller. 28 */ 29 static void Dalvik_dalvik_system_VMStack_getCallingClassLoader(const u4* args, 30 JValue* pResult) 31 { 32 ClassObject* clazz = dvmGetCaller2Class(dvmThreadSelf()->curFrame); 33 34 UNUSED_PARAMETER(args); 35 36 if (clazz == NULL) 37 RETURN_PTR(NULL); 38 RETURN_PTR(clazz->classLoader); 39 } 40 41 /* 42 * public static ClassLoader getCallingClassLoader2() 43 * 44 * Return the defining class loader of the caller's caller's caller. 45 */ 46 static void Dalvik_dalvik_system_VMStack_getCallingClassLoader2(const u4* args, 47 JValue* pResult) 48 { 49 ClassObject* clazz = dvmGetCaller3Class(dvmThreadSelf()->curFrame); 50 51 UNUSED_PARAMETER(args); 52 53 if (clazz == NULL) 54 RETURN_PTR(NULL); 55 RETURN_PTR(clazz->classLoader); 56 } 57 58 /* 59 * public static Class<?> getStackClass2() 60 * 61 * Returns the class of the caller's caller's caller. 62 */ 63 static void Dalvik_dalvik_system_VMStack_getStackClass2(const u4* args, 64 JValue* pResult) 65 { 66 ClassObject* clazz = dvmGetCaller3Class(dvmThreadSelf()->curFrame); 67 68 UNUSED_PARAMETER(args); 69 70 RETURN_PTR(clazz); 71 } 72 73 /* 74 * public static Class<?>[] getClasses(int maxDepth, boolean stopAtPrivileged) 75 * 76 * Create an array of classes for the methods on the stack, skipping the 77 * first two and all reflection methods. If "stopAtPrivileged" is set, 78 * stop shortly after we encounter a privileged class. 79 */ 80 static void Dalvik_dalvik_system_VMStack_getClasses(const u4* args, 81 JValue* pResult) 82 { 83 /* note "maxSize" is unsigned, so -1 turns into a very large value */ 84 unsigned int maxSize = args[0]; 85 bool stopAtPrivileged = args[1]; 86 unsigned int size = 0; 87 const unsigned int kSkip = 2; 88 const Method** methods = NULL; 89 int methodCount; 90 91 /* 92 * Get an array with the stack trace in it. 93 */ 94 if (!dvmCreateStackTraceArray(dvmThreadSelf()->curFrame, &methods, 95 &methodCount)) 96 { 97 LOGE("Failed to create stack trace array\n"); 98 dvmThrowException("Ljava/lang/InternalError;", NULL); 99 RETURN_VOID(); 100 } 101 102 //int i; 103 //LOGI("dvmCreateStackTraceArray results:\n"); 104 //for (i = 0; i < methodCount; i++) { 105 // LOGI(" %2d: %s.%s\n", 106 // i, methods[i]->clazz->descriptor, methods[i]->name); 107 //} 108 109 /* 110 * Run through the array and count up how many elements there are. 111 */ 112 unsigned int idx; 113 for (idx = kSkip; (int) idx < methodCount && size < maxSize; idx++) { 114 const Method* meth = methods[idx]; 115 116 if (dvmIsReflectionMethod(meth)) 117 continue; 118 119 if (stopAtPrivileged && dvmIsPrivilegedMethod(meth)) { 120 /* 121 * We want the last element of the array to be the caller of 122 * the privileged method, so we want to include the privileged 123 * method and the next one. 124 */ 125 if (maxSize > size + 2) 126 maxSize = size + 2; 127 } 128 129 size++; 130 } 131 132 /* 133 * Create an array object to hold the classes. 134 * TODO: can use gDvm.classJavaLangClassArray here? 135 */ 136 ClassObject* classArrayClass = NULL; 137 ArrayObject* classes = NULL; 138 classArrayClass = dvmFindArrayClass("[Ljava/lang/Class;", NULL); 139 if (classArrayClass == NULL) { 140 LOGW("Unable to find java.lang.Class array class\n"); 141 goto bail; 142 } 143 classes = dvmAllocArray(classArrayClass, size, kObjectArrayRefWidth, 144 ALLOC_DEFAULT); 145 if (classes == NULL) { 146 LOGW("Unable to allocate class array (%d elems)\n", size); 147 goto bail; 148 } 149 150 /* 151 * Fill in the array. 152 */ 153 unsigned int objCount = 0; 154 for (idx = kSkip; (int) idx < methodCount; idx++) { 155 if (dvmIsReflectionMethod(methods[idx])) { 156 continue; 157 } 158 dvmSetObjectArrayElement(classes, objCount, 159 (Object *)methods[idx]->clazz); 160 objCount++; 161 } 162 assert(objCount == classes->length); 163 164 bail: 165 free(methods); 166 dvmReleaseTrackedAlloc((Object*) classes, NULL); 167 RETURN_PTR(classes); 168 } 169 170 /* 171 * public static StackTraceElement[] getThreadStackTrace(Thread t) 172 * 173 * Retrieve the stack trace of the specified thread and return it as an 174 * array of StackTraceElement. Returns NULL on failure. 175 */ 176 static void Dalvik_dalvik_system_VMStack_getThreadStackTrace(const u4* args, 177 JValue* pResult) 178 { 179 Object* targetThreadObj = (Object*) args[0]; 180 Thread* self = dvmThreadSelf(); 181 Thread* thread; 182 int* traceBuf; 183 184 assert(targetThreadObj != NULL); 185 186 dvmLockThreadList(self); 187 188 /* 189 * Make sure the thread is still alive and in the list. 190 */ 191 for (thread = gDvm.threadList; thread != NULL; thread = thread->next) { 192 if (thread->threadObj == targetThreadObj) 193 break; 194 } 195 if (thread == NULL) { 196 LOGI("VMStack.getThreadStackTrace: threadObj %p not active\n", 197 targetThreadObj); 198 dvmUnlockThreadList(); 199 RETURN_PTR(NULL); 200 } 201 202 /* 203 * Suspend the thread, pull out the stack trace, then resume the thread 204 * and release the thread list lock. If we're being asked to examine 205 * our own stack trace, skip the suspend/resume. 206 */ 207 int stackDepth = -1; 208 if (thread != self) 209 dvmSuspendThread(thread); 210 traceBuf = dvmFillInStackTraceRaw(thread, &stackDepth); 211 if (thread != self) 212 dvmResumeThread(thread); 213 dvmUnlockThreadList(); 214 215 /* 216 * Convert the raw buffer into an array of StackTraceElement. 217 */ 218 ArrayObject* trace = dvmGetStackTraceRaw(traceBuf, stackDepth); 219 free(traceBuf); 220 RETURN_PTR(trace); 221 } 222 223 const DalvikNativeMethod dvm_dalvik_system_VMStack[] = { 224 { "getCallingClassLoader", "()Ljava/lang/ClassLoader;", 225 Dalvik_dalvik_system_VMStack_getCallingClassLoader }, 226 { "getCallingClassLoader2", "()Ljava/lang/ClassLoader;", 227 Dalvik_dalvik_system_VMStack_getCallingClassLoader2 }, 228 { "getStackClass2", "()Ljava/lang/Class;", 229 Dalvik_dalvik_system_VMStack_getStackClass2 }, 230 { "getClasses", "(IZ)[Ljava/lang/Class;", 231 Dalvik_dalvik_system_VMStack_getClasses }, 232 { "getThreadStackTrace", "(Ljava/lang/Thread;)[Ljava/lang/StackTraceElement;", 233 Dalvik_dalvik_system_VMStack_getThreadStackTrace }, 234 { NULL, NULL, NULL }, 235 }; 236