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