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 */
Dalvik_dalvik_system_VMStack_getCallingClassLoader(const u4 * args,JValue * pResult)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 */
Dalvik_dalvik_system_VMStack_getStackClass2(const u4 * args,JValue * pResult)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 */
Dalvik_dalvik_system_VMStack_getClasses(const u4 * args,JValue * pResult)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 */
getTraceBuf(Object * targetThreadObj,size_t * pStackDepth)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 */
Dalvik_dalvik_system_VMStack_getThreadStackTrace(const u4 * args,JValue * pResult)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 */
Dalvik_dalvik_system_VMStack_fillStackTraceElements(const u4 * args,JValue * pResult)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