dalvik_system_VMStack.cpp revision e8e1ddccd616e8226b7cc1e4e9fdb327429249e8
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 Class<?> getStackClass2()
44 *
45 * Returns the class of the caller's caller's caller.
46 */
47static 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 */
65static 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 */
135static 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 */
180static 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 */
204static 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
226const 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