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