• 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 "native/InternalNativePriv.h"
22 
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 = dvmGetCaller2Class(dvmThreadSelf()->curFrame);
33 
34     UNUSED_PARAMETER(args);
35 
36     if (clazz == NULL)
37         RETURN_PTR(NULL);
38     RETURN_PTR(clazz->classLoader);
39 }
40 
41 /*
42  * public static ClassLoader getCallingClassLoader2()
43  *
44  * Return the defining class loader of the caller's caller's caller.
45  */
Dalvik_dalvik_system_VMStack_getCallingClassLoader2(const u4 * args,JValue * pResult)46 static void Dalvik_dalvik_system_VMStack_getCallingClassLoader2(const u4* args,
47     JValue* pResult)
48 {
49     ClassObject* clazz = dvmGetCaller3Class(dvmThreadSelf()->curFrame);
50 
51     UNUSED_PARAMETER(args);
52 
53     if (clazz == NULL)
54         RETURN_PTR(NULL);
55     RETURN_PTR(clazz->classLoader);
56 }
57 
58 /*
59  * public static Class<?>[] getClasses(int maxDepth, boolean stopAtPrivileged)
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     unsigned int maxSize = args[0];
70     bool stopAtPrivileged = args[1];
71     unsigned int size = 0;
72     const unsigned int kSkip = 2;
73     const Method** methods = NULL;
74     int methodCount;
75 
76     /*
77      * Get an array with the stack trace in it.
78      */
79     if (!dvmCreateStackTraceArray(dvmThreadSelf()->curFrame, &methods,
80             &methodCount))
81     {
82         LOGE("Failed to create stack trace array\n");
83         dvmThrowException("Ljava/lang/InternalError;", NULL);
84         RETURN_VOID();
85     }
86 
87     //int i;
88     //LOGI("dvmCreateStackTraceArray results:\n");
89     //for (i = 0; i < methodCount; i++) {
90     //    LOGI(" %2d: %s.%s\n",
91     //        i, methods[i]->clazz->descriptor, methods[i]->name);
92     //}
93 
94     /*
95      * Run through the array and count up how many elements there are.
96      */
97     unsigned int idx;
98     for (idx = kSkip; (int) idx < methodCount && size < maxSize; idx++) {
99         const Method* meth = methods[idx];
100 
101         if (dvmIsReflectionMethod(meth))
102             continue;
103 
104         if (stopAtPrivileged && dvmIsPrivilegedMethod(meth)) {
105             /*
106              * We want the last element of the array to be the caller of
107              * the privileged method, so we want to include the privileged
108              * method and the next one.
109              */
110             if (maxSize > size + 2)
111                 maxSize = size + 2;
112         }
113 
114         size++;
115     }
116 
117     /*
118      * Create an array object to hold the classes.
119      * TODO: can use gDvm.classJavaLangClassArray here?
120      */
121     ClassObject* classArrayClass = NULL;
122     ArrayObject* classes = NULL;
123     classArrayClass = dvmFindArrayClass("[Ljava/lang/Class;", NULL);
124     if (classArrayClass == NULL) {
125         LOGW("Unable to find java.lang.Class array class\n");
126         goto bail;
127     }
128     classes = dvmAllocArray(classArrayClass, size, kObjectArrayRefWidth,
129                 ALLOC_DEFAULT);
130     if (classes == NULL) {
131         LOGW("Unable to allocate class array (%d elems)\n", size);
132         goto bail;
133     }
134 
135     /*
136      * Fill in the array.
137      */
138     ClassObject** objects = (ClassObject**) classes->contents;
139 
140     unsigned int sidx = 0;
141     for (idx = kSkip; (int) idx < methodCount && sidx < size; idx++) {
142         const Method* meth = methods[idx];
143 
144         if (dvmIsReflectionMethod(meth))
145             continue;
146 
147         *objects++ = meth->clazz;
148         sidx++;
149     }
150 
151 bail:
152     free(methods);
153     dvmReleaseTrackedAlloc((Object*) classes, NULL);
154     RETURN_PTR(classes);
155 }
156 
157 /*
158  * public static StackTraceElement[] getThreadStackTrace(Thread t)
159  *
160  * Retrieve the stack trace of the specified thread and return it as an
161  * array of StackTraceElement.  Returns NULL on failure.
162  */
Dalvik_dalvik_system_VMStack_getThreadStackTrace(const u4 * args,JValue * pResult)163 static void Dalvik_dalvik_system_VMStack_getThreadStackTrace(const u4* args,
164     JValue* pResult)
165 {
166     Object* targetThreadObj = (Object*) args[0];
167     Thread* self = dvmThreadSelf();
168     Thread* thread;
169     int* traceBuf;
170 
171     assert(targetThreadObj != NULL);
172 
173     dvmLockThreadList(self);
174 
175     /*
176      * Make sure the thread is still alive and in the list.
177      */
178     for (thread = gDvm.threadList; thread != NULL; thread = thread->next) {
179         if (thread->threadObj == targetThreadObj)
180             break;
181     }
182     if (thread == NULL) {
183         LOGI("VMStack.getThreadStackTrace: threadObj %p not active\n",
184             targetThreadObj);
185         dvmUnlockThreadList();
186         RETURN_PTR(NULL);
187     }
188 
189     /*
190      * Suspend the thread, pull out the stack trace, then resume the thread
191      * and release the thread list lock.  If we're being asked to examine
192      * our own stack trace, skip the suspend/resume.
193      */
194     int stackDepth = -1;
195     if (thread != self)
196         dvmSuspendThread(thread);
197     traceBuf = dvmFillInStackTraceRaw(thread, &stackDepth);
198     if (thread != self)
199         dvmResumeThread(thread);
200     dvmUnlockThreadList();
201 
202     /*
203      * Convert the raw buffer into an array of StackTraceElement.
204      */
205     ArrayObject* trace = dvmGetStackTraceRaw(traceBuf, stackDepth);
206     free(traceBuf);
207     RETURN_PTR(trace);
208 }
209 
210 const DalvikNativeMethod dvm_dalvik_system_VMStack[] = {
211     { "getCallingClassLoader",  "()Ljava/lang/ClassLoader;",
212         Dalvik_dalvik_system_VMStack_getCallingClassLoader },
213     { "getCallingClassLoader2", "()Ljava/lang/ClassLoader;",
214         Dalvik_dalvik_system_VMStack_getCallingClassLoader2 },
215     { "getClasses",             "(IZ)[Ljava/lang/Class;",
216         Dalvik_dalvik_system_VMStack_getClasses },
217     { "getThreadStackTrace",    "(Ljava/lang/Thread;)[Ljava/lang/StackTraceElement;",
218         Dalvik_dalvik_system_VMStack_getThreadStackTrace },
219     { NULL, NULL, NULL },
220 };
221 
222