• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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