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 "UniquePtr.h" 22 #include "native/InternalNativePriv.h" 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 = 33 dvmGetCaller2Class(dvmThreadSelf()->interpSave.curFrame); 34 35 UNUSED_PARAMETER(args); 36 37 if (clazz == NULL) 38 RETURN_PTR(NULL); 39 RETURN_PTR(clazz->classLoader); 40 } 41 42 /* 43 * public static Class<?> getStackClass2() 44 * 45 * Returns the class of the caller's caller's caller. 46 */ 47 static void Dalvik_dalvik_system_VMStack_getStackClass2(const u4* args, 48 JValue* pResult) 49 { 50 ClassObject* clazz = 51 dvmGetCaller3Class(dvmThreadSelf()->interpSave.curFrame); 52 53 UNUSED_PARAMETER(args); 54 55 RETURN_PTR(clazz); 56 } 57 58 /* 59 * public static Class<?>[] getClasses(int maxDepth) 60 * 61 * Create an array of classes for the methods on the stack, skipping the 62 * first two and all reflection methods. If "stopAtPrivileged" is set, 63 * stop shortly after we encounter a privileged class. 64 */ 65 static void Dalvik_dalvik_system_VMStack_getClasses(const u4* args, 66 JValue* pResult) 67 { 68 /* note "maxSize" is unsigned, so -1 turns into a very large value */ 69 size_t maxSize = args[0]; 70 size_t size = 0; 71 const size_t kSkip = 2; 72 73 /* 74 * Get an array with the stack trace in it. 75 */ 76 void *fp = dvmThreadSelf()->interpSave.curFrame; 77 size_t depth = dvmComputeExactFrameDepth(fp); 78 UniquePtr<const Method*[]> methods(new const Method*[depth]); 79 dvmFillStackTraceArray(fp, methods.get(), depth); 80 81 /* 82 * Run through the array and count up how many elements there are. 83 */ 84 for (size_t i = kSkip; i < depth && size < maxSize; ++i) { 85 const Method* meth = methods[i]; 86 87 if (dvmIsReflectionMethod(meth)) 88 continue; 89 90 size++; 91 } 92 93 /* 94 * Create an array object to hold the classes. 95 * TODO: can use gDvm.classJavaLangClassArray here? 96 */ 97 ClassObject* classArrayClass = dvmFindArrayClass("[Ljava/lang/Class;", 98 NULL); 99 if (classArrayClass == NULL) { 100 ALOGW("Unable to find java.lang.Class array class"); 101 return; 102 } 103 ArrayObject* classes = dvmAllocArrayByClass(classArrayClass, 104 size, 105 ALLOC_DEFAULT); 106 if (classes == NULL) { 107 ALOGW("Unable to allocate class array of %zd elements", size); 108 return; 109 } 110 111 /* 112 * Fill in the array. 113 */ 114 size_t objCount = 0; 115 for (size_t i = kSkip; i < depth; ++i) { 116 if (dvmIsReflectionMethod(methods[i])) { 117 continue; 118 } 119 Object* klass = (Object *)methods[i]->clazz; 120 dvmSetObjectArrayElement(classes, objCount, klass); 121 objCount++; 122 } 123 assert(objCount == classes->length); 124 125 dvmReleaseTrackedAlloc((Object*)classes, NULL); 126 RETURN_PTR(classes); 127 } 128 129 /* 130 * Return a trace buffer for the specified thread or NULL if the 131 * thread is not still alive. *depth is set to the length of a 132 * non-NULL trace buffer. Caller is responsible for freeing the trace 133 * buffer. 134 */ 135 static int* getTraceBuf(Object* targetThreadObj, size_t* pStackDepth) 136 { 137 Thread* self = dvmThreadSelf(); 138 Thread* thread; 139 int* traceBuf; 140 141 assert(targetThreadObj != NULL); 142 143 dvmLockThreadList(self); 144 145 /* 146 * Make sure the thread is still alive and in the list. 147 */ 148 for (thread = gDvm.threadList; thread != NULL; thread = thread->next) { 149 if (thread->threadObj == targetThreadObj) 150 break; 151 } 152 if (thread == NULL) { 153 ALOGI("VMStack.getTraceBuf: threadObj %p not active", 154 targetThreadObj); 155 dvmUnlockThreadList(); 156 return NULL; 157 } 158 159 /* 160 * Suspend the thread, pull out the stack trace, then resume the thread 161 * and release the thread list lock. If we're being asked to examine 162 * our own stack trace, skip the suspend/resume. 163 */ 164 if (thread != self) 165 dvmSuspendThread(thread); 166 traceBuf = dvmFillInStackTraceRaw(thread, pStackDepth); 167 if (thread != self) 168 dvmResumeThread(thread); 169 dvmUnlockThreadList(); 170 171 return traceBuf; 172 } 173 174 /* 175 * public static StackTraceElement[] getThreadStackTrace(Thread t) 176 * 177 * Retrieve the stack trace of the specified thread and return it as an 178 * array of StackTraceElement. Returns NULL on failure. 179 */ 180 static void Dalvik_dalvik_system_VMStack_getThreadStackTrace(const u4* args, 181 JValue* pResult) 182 { 183 Object* targetThreadObj = (Object*) args[0]; 184 size_t stackDepth; 185 int* traceBuf = getTraceBuf(targetThreadObj, &stackDepth); 186 187 if (traceBuf == NULL) 188 RETURN_PTR(NULL); 189 190 /* 191 * Convert the raw buffer into an array of StackTraceElement. 192 */ 193 ArrayObject* trace = dvmGetStackTraceRaw(traceBuf, stackDepth); 194 free(traceBuf); 195 RETURN_PTR(trace); 196 } 197 198 /* 199 * public static int fillStackTraceElements(Thread t, StackTraceElement[] stackTraceElements) 200 * 201 * Retrieve a partial stack trace of the specified thread and return 202 * the number of frames filled. Returns 0 on failure. 203 */ 204 static void Dalvik_dalvik_system_VMStack_fillStackTraceElements(const u4* args, 205 JValue* pResult) 206 { 207 Object* targetThreadObj = (Object*) args[0]; 208 ArrayObject* steArray = (ArrayObject*) args[1]; 209 size_t stackDepth; 210 int* traceBuf = getTraceBuf(targetThreadObj, &stackDepth); 211 212 if (traceBuf == NULL) 213 RETURN_PTR(NULL); 214 215 /* 216 * Set the raw buffer into an array of StackTraceElement. 217 */ 218 if (stackDepth > steArray->length) { 219 stackDepth = steArray->length; 220 } 221 dvmFillStackTraceElements(traceBuf, stackDepth, steArray); 222 free(traceBuf); 223 RETURN_INT(stackDepth); 224 } 225 226 const DalvikNativeMethod dvm_dalvik_system_VMStack[] = { 227 { "getCallingClassLoader", "()Ljava/lang/ClassLoader;", 228 Dalvik_dalvik_system_VMStack_getCallingClassLoader }, 229 { "getStackClass2", "()Ljava/lang/Class;", 230 Dalvik_dalvik_system_VMStack_getStackClass2 }, 231 { "getClasses", "(I)[Ljava/lang/Class;", 232 Dalvik_dalvik_system_VMStack_getClasses }, 233 { "getThreadStackTrace", "(Ljava/lang/Thread;)[Ljava/lang/StackTraceElement;", 234 Dalvik_dalvik_system_VMStack_getThreadStackTrace }, 235 { "fillStackTraceElements", "(Ljava/lang/Thread;[Ljava/lang/StackTraceElement;)I", 236 Dalvik_dalvik_system_VMStack_fillStackTraceElements }, 237 { NULL, NULL, NULL }, 238 }; 239