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