Exception.cpp revision 686e1e23324f1c1f358f29f13f23e57b41c00eaa
1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * you may not use this file except in compliance with the License.
6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * You may obtain a copy of the License at
7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * See the License for the specific language governing permissions and
14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * limitations under the License.
15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
16f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Exception handling.
18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "Dalvik.h"
20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "libdex/DexCatch.h"
21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <stdlib.h>
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectNotes on Exception Handling
26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectWe have one fairly sticky issue to deal with: creating the exception stack
28f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projecttrace.  The trouble is that we need the current value of the program
29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectcounter for the method now being executed, but that's only held in a local
30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvariable or hardware register in the main interpreter loop.
31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectThe exception mechanism requires that the current stack trace be associated
33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectwith a Throwable at the time the Throwable is constructed.  The construction
34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectmay or may not be associated with a throw.  We have three situations to
35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectconsider:
36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project (1) A Throwable is created with a "new Throwable" statement in the
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     application code, for immediate or deferred use with a "throw" statement.
39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project (2) The VM throws an exception from within the interpreter core, e.g.
40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     after an integer divide-by-zero.
41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project (3) The VM throws an exception from somewhere deeper down, e.g. while
42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     trying to link a class.
43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectWe need to have the current value for the PC, which means that for
45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectsituation (3) the interpreter loop must copy it to an externally-accessible
46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectlocation before handling any opcode that could cause the VM to throw
47f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectan exception.  We can't store it globally, because the various threads
48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectwould trample each other.  We can't store it in the Thread structure,
49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbecause it'll get overwritten as soon as the Throwable constructor starts
50f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectexecuting.  It needs to go on the stack, but our stack frames hold the
51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectcaller's *saved* PC, not the current PC.
52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectSituation #1 doesn't require special handling.  Situation #2 could be dealt
54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectwith by passing the PC into the exception creation function.  The trick
55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectis to solve situation #3 in a way that adds minimal overhead to common
56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectoperations.  Making it more costly to throw an exception is acceptable.
57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectThere are a few ways to deal with this:
59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project (a) Change "savedPc" to "currentPc" in the stack frame.  All of the
61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     stack logic gets offset by one frame.  The current PC is written
62f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     to the current stack frame when necessary.
63f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project (b) Write the current PC into the current stack frame, but without
64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     replacing "savedPc".  The JNI local refs pointer, which is only
65f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     used for native code, can be overloaded to save space.
66f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project (c) In dvmThrowException(), push an extra stack frame on, with the
67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     current PC in it.  The current PC is written into the Thread struct
68f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     when necessary, and copied out when the VM throws.
69f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project (d) Before doing something that might throw an exception, push a
70f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     temporary frame on with the saved PC in it.
71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
72f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectSolution (a) is the simplest, but breaks Dalvik's goal of mingling native
73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectand interpreted stacks.
74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectSolution (b) retains the simplicity of (a) without rearranging the stack,
76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbut now in some cases we're storing the PC twice, which feels wrong.
77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectSolution (c) usually works, because we push the saved PC onto the stack
79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbefore the Throwable construction can overwrite the copy in Thread.  One
80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectway solution (c) could break is:
81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project - Interpreter saves the PC
82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project - Execute some bytecode, which runs successfully (and alters the saved PC)
83f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project - Throw an exception before re-saving the PC (i.e in the same opcode)
84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectThis is a risk for anything that could cause <clinit> to execute, e.g.
85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectexecuting a static method or accessing a static field.  Attemping to access
86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projecta field that doesn't exist in a class that does exist might cause this.
87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectIt may be possible to simply bracket the dvmCallMethod*() functions to
88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectsave/restore it.
89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
90f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectSolution (d) incurs additional overhead, but may have other benefits (e.g.
91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectit's easy to find the stack frames that should be removed before storage
92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectin the Throwable).
93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectCurrent plan is option (b), because it's simple, fast, and doesn't change
95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectthe way the stack works.
96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project*/
97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* fwd */
99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic bool initException(Object* exception, const char* msg, Object* cause,
100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    Thread* self);
101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Cache pointers to some of the exception classes we use locally.
105686e1e23324f1c1f358f29f13f23e57b41c00eaaAndy McFadden *
106686e1e23324f1c1f358f29f13f23e57b41c00eaaAndy McFadden * Note this is NOT called during dexopt optimization.  Some of the fields
107686e1e23324f1c1f358f29f13f23e57b41c00eaaAndy McFadden * are initialized by the verifier (dvmVerifyCodeFlow).
108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbool dvmExceptionStartup(void)
110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gDvm.classJavaLangThrowable =
112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmFindSystemClassNoInit("Ljava/lang/Throwable;");
113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gDvm.classJavaLangRuntimeException =
114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmFindSystemClassNoInit("Ljava/lang/RuntimeException;");
115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gDvm.classJavaLangError =
116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmFindSystemClassNoInit("Ljava/lang/Error;");
117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gDvm.classJavaLangStackTraceElement =
118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmFindSystemClassNoInit("Ljava/lang/StackTraceElement;");
119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gDvm.classJavaLangStackTraceElementArray =
120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmFindArrayClass("[Ljava/lang/StackTraceElement;", NULL);
121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (gDvm.classJavaLangThrowable == NULL ||
122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        gDvm.classJavaLangStackTraceElement == NULL ||
123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        gDvm.classJavaLangStackTraceElementArray == NULL)
124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGE("Could not find one or more essential exception classes\n");
126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return false;
127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Find the constructor.  Note that, unlike other saved method lookups,
131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * we're using a Method* instead of a vtable offset.  This is because
132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * constructors don't have vtable offsets.  (Also, since we're creating
133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * the object in question, it's impossible for anyone to sub-class it.)
134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    Method* meth;
136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    meth = dvmFindDirectMethodByDescriptor(gDvm.classJavaLangStackTraceElement,
137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        "<init>", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)V");
138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (meth == NULL) {
139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGE("Unable to find constructor for StackTraceElement\n");
140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return false;
141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gDvm.methJavaLangStackTraceElement_init = meth;
143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* grab an offset for the stackData field */
145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gDvm.offJavaLangThrowable_stackState =
146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmFindFieldOffset(gDvm.classJavaLangThrowable,
147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            "stackState", "Ljava/lang/Object;");
148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (gDvm.offJavaLangThrowable_stackState < 0) {
149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGE("Unable to find Throwable.stackState\n");
150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return false;
151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* and one for the message field, in case we want to show it */
154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gDvm.offJavaLangThrowable_message =
155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmFindFieldOffset(gDvm.classJavaLangThrowable,
156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            "detailMessage", "Ljava/lang/String;");
157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (gDvm.offJavaLangThrowable_message < 0) {
158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGE("Unable to find Throwable.detailMessage\n");
159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return false;
160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* and one for the cause field, just 'cause */
163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gDvm.offJavaLangThrowable_cause =
164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmFindFieldOffset(gDvm.classJavaLangThrowable,
165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            "cause", "Ljava/lang/Throwable;");
166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (gDvm.offJavaLangThrowable_cause < 0) {
167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGE("Unable to find Throwable.cause\n");
168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return false;
169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return true;
172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Clean up.
176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmExceptionShutdown(void)
178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    // nothing to do
180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Create a Throwable and throw an exception in the current thread (where
185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * "throwing" just means "set the thread's exception pointer").
186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * "msg" and/or "cause" may be NULL.
188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * If we have a bad exception hierarchy -- something in Throwable.<init>
190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * is missing -- then every attempt to throw an exception will result
191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * in another exception.  Exceptions are generally allowed to "chain"
192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * to other exceptions, so it's hard to auto-detect this problem.  It can
193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * only happen if the system classes are broken, so it's probably not
194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * worth spending cycles to detect it.
195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We do have one case to worry about: if the classpath is completely
197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * wrong, we'll go into a death spin during startup because we can't find
198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * the initial class and then we can't find NoClassDefFoundError.  We have
199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * to handle this case.
200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * [Do we want to cache pointers to common exception classes?]
202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmThrowChainedException(const char* exceptionDescriptor, const char* msg,
204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    Object* cause)
205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    ClassObject* excepClass;
207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    LOGV("THROW '%s' msg='%s' cause=%s\n",
209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        exceptionDescriptor, msg,
210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        (cause != NULL) ? cause->clazz->descriptor : "(none)");
211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (gDvm.initializing) {
213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (++gDvm.initExceptionCount >= 2) {
214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            LOGE("Too many exceptions during init (failed on '%s' '%s')\n",
215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                exceptionDescriptor, msg);
216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            dvmAbort();
217f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
220f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    excepClass = dvmFindSystemClass(exceptionDescriptor);
221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (excepClass == NULL) {
222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * We couldn't find the exception class.  The attempt to find a
224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * nonexistent class should have raised an exception.  If no
225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * exception is currently raised, then we're pretty clearly unable
226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * to throw ANY sort of exception, and we need to pack it in.
227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         *
228f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * If we were able to throw the "class load failed" exception,
229f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * stick with that.  Ideally we'd stuff the original exception
230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * into the "cause" field, but since we can't find it we can't
231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * do that.  The exception class name should be in the "message"
232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * field.
233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
234f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (!dvmCheckException(dvmThreadSelf())) {
235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            LOGE("FATAL: unable to throw exception (failed on '%s' '%s')\n",
236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                exceptionDescriptor, msg);
237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            dvmAbort();
238f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
239f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return;
240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmThrowChainedExceptionByClass(excepClass, msg, cause);
243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
244f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
245f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
246f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Start/continue throwing process now that we have a class reference.
247f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
248f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmThrowChainedExceptionByClass(ClassObject* excepClass, const char* msg,
249f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    Object* cause)
250f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
251f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    Thread* self = dvmThreadSelf();
252f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    Object* exception;
253f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
254f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* make sure the exception is initialized */
255f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (!dvmIsClassInitialized(excepClass) && !dvmInitClass(excepClass)) {
256f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGE("ERROR: unable to initialize exception class '%s'\n",
257f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            excepClass->descriptor);
258f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (strcmp(excepClass->descriptor, "Ljava/lang/InternalError;") == 0)
259f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            dvmAbort();
260f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmThrowChainedException("Ljava/lang/InternalError;",
261f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            "failed to init original exception class", cause);
262f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return;
263f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
264f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    exception = dvmAllocObject(excepClass, ALLOC_DEFAULT);
266f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (exception == NULL) {
267f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
268f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * We're in a lot of trouble.  We might be in the process of
269f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * throwing an out-of-memory exception, in which case the
270f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * pre-allocated object will have been thrown when our object alloc
271f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * failed.  So long as there's an exception raised, return and
272f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * allow the system to try to recover.  If not, something is broken
273f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * and we need to bail out.
274f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
275f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (dvmCheckException(self))
276f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            goto bail;
277f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGE("FATAL: unable to allocate exception '%s' '%s'\n",
278f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            excepClass->descriptor, msg != NULL ? msg : "(no msg)");
279f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmAbort();
280f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
281f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
282f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
283f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Init the exception.
284f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
285f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (gDvm.optimizing) {
286f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* need the exception object, but can't invoke interpreted code */
287f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGV("Skipping init of exception %s '%s'\n",
288f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            excepClass->descriptor, msg);
289f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } else {
290f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        assert(excepClass == exception->clazz);
291f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (!initException(exception, msg, cause, self)) {
292f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
293f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * Whoops.  If we can't initialize the exception, we can't use
294f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * it.  If there's an exception already set, the constructor
295f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * probably threw an OutOfMemoryError.
296f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
297f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (!dvmCheckException(self)) {
298f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                /*
299f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * We're required to throw something, so we just
300f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * throw the pre-constructed internal error.
301f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 */
302f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                self->exception = gDvm.internalErrorObj;
303f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
304f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            goto bail;
305f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
306f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
307f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
308f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    self->exception = exception;
309f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
310f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbail:
311f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmReleaseTrackedAlloc(exception, self);
312f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
313f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
314f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
315f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Throw the named exception using the dotted form of the class
316f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * descriptor as the exception message, and with the specified cause.
317f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
318f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmThrowChainedExceptionWithClassMessage(const char* exceptionDescriptor,
319f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    const char* messageDescriptor, Object* cause)
320f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
321f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    char* message = dvmDescriptorToDot(messageDescriptor);
322f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
323f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmThrowChainedException(exceptionDescriptor, message, cause);
324f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    free(message);
325f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
326f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
327f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
328f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Like dvmThrowExceptionWithMessageFromDescriptor, but take a
329f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * class object instead of a name.
330f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
331f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmThrowExceptionByClassWithClassMessage(ClassObject* exceptionClass,
332f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    const char* messageDescriptor)
333f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
334f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    char* message = dvmDescriptorToName(messageDescriptor);
335f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
336f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmThrowExceptionByClass(exceptionClass, message);
337f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    free(message);
338f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
339f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
340f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
341f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Initialize an exception with an appropriate constructor.
342f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
343f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * "exception" is the exception object to initialize.
344f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Either or both of "msg" and "cause" may be null.
345f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * "self" is dvmThreadSelf(), passed in so we don't have to look it up again.
346f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
347f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * If the process of initializing the exception causes another
348f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * exception (e.g., OutOfMemoryError) to be thrown, return an error
349f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * and leave self->exception intact.
350f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
351f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic bool initException(Object* exception, const char* msg, Object* cause,
352f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    Thread* self)
353f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
354f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    enum {
355f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        kInitUnknown,
356f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        kInitNoarg,
357f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        kInitMsg,
358f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        kInitMsgThrow,
359f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        kInitThrow
360f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } initKind = kInitUnknown;
361f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    Method* initMethod = NULL;
362f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    ClassObject* excepClass = exception->clazz;
363f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    StringObject* msgStr = NULL;
364f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    bool result = false;
365f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    bool needInitCause = false;
366f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
367f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(self != NULL);
368f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(self->exception == NULL);
369f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
370f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* if we have a message, create a String */
371f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (msg == NULL)
372f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        msgStr = NULL;
373f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    else {
374f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        msgStr = dvmCreateStringFromCstr(msg, ALLOC_DEFAULT);
375f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (msgStr == NULL) {
376f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            LOGW("Could not allocate message string \"%s\" while "
377f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    "throwing internal exception (%s)\n",
378f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    msg, excepClass->descriptor);
379f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            goto bail;
380f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
381f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
382f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
383686e1e23324f1c1f358f29f13f23e57b41c00eaaAndy McFadden    if (cause != NULL) {
384686e1e23324f1c1f358f29f13f23e57b41c00eaaAndy McFadden        if (!dvmInstanceof(cause->clazz, gDvm.classJavaLangThrowable)) {
385686e1e23324f1c1f358f29f13f23e57b41c00eaaAndy McFadden            LOGE("Tried to init exception with cause '%s'\n",
386686e1e23324f1c1f358f29f13f23e57b41c00eaaAndy McFadden                cause->clazz->descriptor);
387686e1e23324f1c1f358f29f13f23e57b41c00eaaAndy McFadden            dvmAbort();
388686e1e23324f1c1f358f29f13f23e57b41c00eaaAndy McFadden        }
389686e1e23324f1c1f358f29f13f23e57b41c00eaaAndy McFadden    }
390686e1e23324f1c1f358f29f13f23e57b41c00eaaAndy McFadden
391f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
392f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * The Throwable class has four public constructors:
393f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *  (1) Throwable()
394f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *  (2) Throwable(String message)
395f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *  (3) Throwable(String message, Throwable cause)  (added in 1.4)
396f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *  (4) Throwable(Throwable cause)                  (added in 1.4)
397f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
398f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * The first two are part of the original design, and most exception
399f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * classes should support them.  The third prototype was used by
400f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * individual exceptions. e.g. ClassNotFoundException added it in 1.2.
401f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * The general "cause" mechanism was added in 1.4.  Some classes,
402f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * such as IllegalArgumentException, initially supported the first
403f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * two, but added the second two in a later release.
404f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
405f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Exceptions may be picky about how their "cause" field is initialized.
406f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * If you call ClassNotFoundException(String), it may choose to
407f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * initialize its "cause" field to null.  Doing so prevents future
408f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * calls to Throwable.initCause().
409f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
410f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * So, if "cause" is not NULL, we need to look for a constructor that
411f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * takes a throwable.  If we can't find one, we fall back on calling
412f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * #1/#2 and making a separate call to initCause().  Passing a null ref
413f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * for "message" into Throwable(String, Throwable) is allowed, but we
414f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * prefer to use the Throwable-only version because it has different
415f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * behavior.
416f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
417f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * java.lang.TypeNotPresentException is a strange case -- it has #3 but
418f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * not #2.  (Some might argue that the constructor is actually not #3,
419f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * because it doesn't take the message string as an argument, but it
420f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * has the same effect and we can work with it here.)
421f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
422f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (cause == NULL) {
423f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (msgStr == NULL) {
424f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            initMethod = dvmFindDirectMethodByDescriptor(excepClass, "<init>", "()V");
425f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            initKind = kInitNoarg;
426f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
427f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            initMethod = dvmFindDirectMethodByDescriptor(excepClass, "<init>",
428f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            "(Ljava/lang/String;)V");
429f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (initMethod != NULL) {
430f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                initKind = kInitMsg;
431f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
432f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                /* no #2, try #3 */
433f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                initMethod = dvmFindDirectMethodByDescriptor(excepClass, "<init>",
434f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                "(Ljava/lang/String;Ljava/lang/Throwable;)V");
435f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (initMethod != NULL)
436f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    initKind = kInitMsgThrow;
437f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
438f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
439f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } else {
440f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (msgStr == NULL) {
441f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            initMethod = dvmFindDirectMethodByDescriptor(excepClass, "<init>",
442f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            "(Ljava/lang/Throwable;)V");
443f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (initMethod != NULL) {
444f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                initKind = kInitThrow;
445f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
446f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                initMethod = dvmFindDirectMethodByDescriptor(excepClass, "<init>", "()V");
447f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                initKind = kInitNoarg;
448f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                needInitCause = true;
449f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
450f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
451f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            initMethod = dvmFindDirectMethodByDescriptor(excepClass, "<init>",
452f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            "(Ljava/lang/String;Ljava/lang/Throwable;)V");
453f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (initMethod != NULL) {
454f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                initKind = kInitMsgThrow;
455f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
456f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                initMethod = dvmFindDirectMethodByDescriptor(excepClass, "<init>",
457f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                "(Ljava/lang/String;)V");
458f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                initKind = kInitMsg;
459f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                needInitCause = true;
460f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
461f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
462f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
463f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
464f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (initMethod == NULL) {
465f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
466f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * We can't find the desired constructor.  This can happen if a
467f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * subclass of java/lang/Throwable doesn't define an expected
468f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * constructor, e.g. it doesn't provide one that takes a string
469f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * when a message has been provided.
470f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
471f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGW("WARNING: exception class '%s' missing constructor "
472f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            "(msg='%s' kind=%d)\n",
473f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            excepClass->descriptor, msg, initKind);
474f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        assert(strcmp(excepClass->descriptor,
475f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                      "Ljava/lang/RuntimeException;") != 0);
476f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmThrowChainedException("Ljava/lang/RuntimeException;",
477f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            "re-throw on exception class missing constructor", NULL);
478f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
479f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
480f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
481f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
482f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Call the constructor with the appropriate arguments.
483f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
484f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    JValue unused;
485f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    switch (initKind) {
486f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case kInitNoarg:
487f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGVV("+++ exc noarg (ic=%d)\n", needInitCause);
488f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmCallMethod(self, initMethod, exception, &unused);
489f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
490f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case kInitMsg:
491f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGVV("+++ exc msg (ic=%d)\n", needInitCause);
492f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmCallMethod(self, initMethod, exception, &unused, msgStr);
493f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
494f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case kInitThrow:
495f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGVV("+++ exc throw");
496f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        assert(!needInitCause);
497f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmCallMethod(self, initMethod, exception, &unused, cause);
498f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
499f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case kInitMsgThrow:
500f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGVV("+++ exc msg+throw");
501f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        assert(!needInitCause);
502f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmCallMethod(self, initMethod, exception, &unused, msgStr, cause);
503f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
504f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    default:
505f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        assert(false);
506f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
507f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
508f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
509f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
510f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * It's possible the constructor has thrown an exception.  If so, we
511f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * return an error and let our caller deal with it.
512f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
513f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (self->exception != NULL) {
514f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGW("Exception thrown (%s) while throwing internal exception (%s)\n",
515f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            self->exception->clazz->descriptor, exception->clazz->descriptor);
516f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
517f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
518f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
519f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
520f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * If this exception was caused by another exception, and we weren't
521f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * able to find a cause-setting constructor, set the "cause" field
522f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * with an explicit call.
523f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
524f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (needInitCause) {
525f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Method* initCause;
526f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        initCause = dvmFindVirtualMethodHierByDescriptor(excepClass, "initCause",
527f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            "(Ljava/lang/Throwable;)Ljava/lang/Throwable;");
528f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (initCause != NULL) {
529f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            dvmCallMethod(self, initCause, exception, &unused, cause);
530f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (self->exception != NULL) {
531f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                /* initCause() threw an exception; return an error and
532f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * let the caller deal with it.
533f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 */
534f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                LOGW("Exception thrown (%s) during initCause() "
535f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        "of internal exception (%s)\n",
536f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        self->exception->clazz->descriptor,
537f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        exception->clazz->descriptor);
538f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                goto bail;
539f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
540f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
541f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            LOGW("WARNING: couldn't find initCause in '%s'\n",
542f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                excepClass->descriptor);
543f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
544f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
545f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
546f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
547f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    result = true;
548f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
549f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbail:
550f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmReleaseTrackedAlloc((Object*) msgStr, self);     // NULL is ok
551f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return result;
552f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
553f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
554f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
555f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
556f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Clear the pending exception and the "initExceptionCount" counter.  This
557f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * is used by the optimization and verification code, which has to run with
558f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * "initializing" set to avoid going into a death-spin if the "class not
559f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * found" exception can't be found.
560f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
561f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * This can also be called when the VM is in a "normal" state, e.g. when
562f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * verifying classes that couldn't be verified at optimization time.  The
563f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * reset of initExceptionCount should be harmless in that case.
564f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
565f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmClearOptException(Thread* self)
566f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
567f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    self->exception = NULL;
568f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gDvm.initExceptionCount = 0;
569f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
570f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
571f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
572f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Returns "true" if this is a "checked" exception, i.e. it's a subclass
573f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * of Throwable (assumed) but not a subclass of RuntimeException or Error.
574f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
575f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbool dvmIsCheckedException(const Object* exception)
576f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
577f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (dvmInstanceof(exception->clazz, gDvm.classJavaLangError) ||
578f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmInstanceof(exception->clazz, gDvm.classJavaLangRuntimeException))
579f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
580f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return false;
581f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } else {
582f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return true;
583f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
584f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
585f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
586f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
587f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Wrap the now-pending exception in a different exception.  This is useful
588f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * for reflection stuff that wants to hand a checked exception back from a
589f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * method that doesn't declare it.
590f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
591f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * If something fails, an (unchecked) exception related to that failure
592f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * will be pending instead.
593f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
594f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmWrapException(const char* newExcepStr)
595f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
596f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    Thread* self = dvmThreadSelf();
597f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    Object* origExcep;
598f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    ClassObject* iteClass;
599f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
600f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    origExcep = dvmGetException(self);
601f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmAddTrackedAlloc(origExcep, self);    // don't let the GC free it
602f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
603f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmClearException(self);                // clear before class lookup
604f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    iteClass = dvmFindSystemClass(newExcepStr);
605f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (iteClass != NULL) {
606f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Object* iteExcep;
607f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Method* initMethod;
608f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
609f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        iteExcep = dvmAllocObject(iteClass, ALLOC_DEFAULT);
610f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (iteExcep != NULL) {
611f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            initMethod = dvmFindDirectMethodByDescriptor(iteClass, "<init>",
612f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            "(Ljava/lang/Throwable;)V");
613f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (initMethod != NULL) {
614f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                JValue unused;
615f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                dvmCallMethod(self, initMethod, iteExcep, &unused,
616f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    origExcep);
617f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
618f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                /* if <init> succeeded, replace the old exception */
619f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (!dvmCheckException(self))
620f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    dvmSetException(self, iteExcep);
621f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
622f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            dvmReleaseTrackedAlloc(iteExcep, NULL);
623f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
624f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /* if initMethod doesn't exist, or failed... */
625f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (!dvmCheckException(self))
626f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                dvmSetException(self, origExcep);
627f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
628f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /* leave OutOfMemoryError pending */
629f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
630f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } else {
631f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* leave ClassNotFoundException pending */
632f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
633f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
634f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(dvmCheckException(self));
635f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmReleaseTrackedAlloc(origExcep, self);
636f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
637f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
638f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
639686e1e23324f1c1f358f29f13f23e57b41c00eaaAndy McFadden * Get the "cause" field from an exception.
640686e1e23324f1c1f358f29f13f23e57b41c00eaaAndy McFadden *
641686e1e23324f1c1f358f29f13f23e57b41c00eaaAndy McFadden * The Throwable class initializes the "cause" field to "this" to
642686e1e23324f1c1f358f29f13f23e57b41c00eaaAndy McFadden * differentiate between being initialized to null and never being
643686e1e23324f1c1f358f29f13f23e57b41c00eaaAndy McFadden * initialized.  We check for that here and convert it to NULL.
644686e1e23324f1c1f358f29f13f23e57b41c00eaaAndy McFadden */
645686e1e23324f1c1f358f29f13f23e57b41c00eaaAndy McFaddenObject* dvmGetExceptionCause(const Object* exception)
646686e1e23324f1c1f358f29f13f23e57b41c00eaaAndy McFadden{
647686e1e23324f1c1f358f29f13f23e57b41c00eaaAndy McFadden    if (!dvmInstanceof(exception->clazz, gDvm.classJavaLangThrowable)) {
648686e1e23324f1c1f358f29f13f23e57b41c00eaaAndy McFadden        LOGE("Tried to get cause from object of type '%s'\n",
649686e1e23324f1c1f358f29f13f23e57b41c00eaaAndy McFadden            exception->clazz->descriptor);
650686e1e23324f1c1f358f29f13f23e57b41c00eaaAndy McFadden        dvmAbort();
651686e1e23324f1c1f358f29f13f23e57b41c00eaaAndy McFadden    }
652686e1e23324f1c1f358f29f13f23e57b41c00eaaAndy McFadden    Object* cause =
653686e1e23324f1c1f358f29f13f23e57b41c00eaaAndy McFadden        dvmGetFieldObject(exception, gDvm.offJavaLangThrowable_cause);
654686e1e23324f1c1f358f29f13f23e57b41c00eaaAndy McFadden    if (cause == exception)
655686e1e23324f1c1f358f29f13f23e57b41c00eaaAndy McFadden        return NULL;
656686e1e23324f1c1f358f29f13f23e57b41c00eaaAndy McFadden    else
657686e1e23324f1c1f358f29f13f23e57b41c00eaaAndy McFadden        return cause;
658686e1e23324f1c1f358f29f13f23e57b41c00eaaAndy McFadden}
659686e1e23324f1c1f358f29f13f23e57b41c00eaaAndy McFadden
660686e1e23324f1c1f358f29f13f23e57b41c00eaaAndy McFadden/*
661f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Print the stack trace of the current exception on stderr.  This is called
662f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * from the JNI ExceptionDescribe call.
663f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
664f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * For consistency we just invoke the Throwable printStackTrace method,
665f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * which might be overridden in the exception object.
666f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
667f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Exceptions thrown during the course of printing the stack trace are
668f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * ignored.
669f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
670f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmPrintExceptionStackTrace(void)
671f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
672f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    Thread* self = dvmThreadSelf();
673f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    Object* exception;
674f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    Method* printMethod;
675f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
676f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    exception = self->exception;
677f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (exception == NULL)
678f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return;
679f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
680f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    self->exception = NULL;
681f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    printMethod = dvmFindVirtualMethodHierByDescriptor(exception->clazz,
682f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    "printStackTrace", "()V");
683f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (printMethod != NULL) {
684f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        JValue unused;
685f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmCallMethod(self, printMethod, exception, &unused);
686f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } else {
687f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGW("WARNING: could not find printStackTrace in %s\n",
688f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            exception->clazz->descriptor);
689f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
690f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
691f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (self->exception != NULL) {
692f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGI("NOTE: exception thrown while printing stack trace: %s\n",
693f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            self->exception->clazz->descriptor);
694f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
695f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
696f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    self->exception = exception;
697f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
698f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
699f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
700f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Search the method's list of exceptions for a match.
701f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
702f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Returns the offset of the catch block on success, or -1 on failure.
703f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
704f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic int findCatchInMethod(Thread* self, const Method* method, int relPc,
705f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    ClassObject* excepClass)
706f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
707f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
708f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Need to clear the exception before entry.  Otherwise, dvmResolveClass
709f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * might think somebody threw an exception while it was loading a class.
710f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
711f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(!dvmCheckException(self));
712f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(!dvmIsNativeMethod(method));
713f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
714f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    LOGVV("findCatchInMethod %s.%s excep=%s depth=%d\n",
715f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        method->clazz->descriptor, method->name, excepClass->descriptor,
716f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmComputeExactFrameDepth(self->curFrame));
717f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
718f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    DvmDex* pDvmDex = method->clazz->pDvmDex;
719f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    const DexCode* pCode = dvmGetMethodCode(method);
720f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    DexCatchIterator iterator;
721f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
722f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (dexFindCatchHandler(&iterator, pCode, relPc)) {
723f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (;;) {
724f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
725f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
726f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (handler == NULL) {
727f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                break;
728f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
729f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
730f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (handler->typeIdx == kDexNoIndex) {
731f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                /* catch-all */
732f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                LOGV("Match on catch-all block at 0x%02x in %s.%s for %s\n",
733f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        relPc, method->clazz->descriptor,
734f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        method->name, excepClass->descriptor);
735f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                return handler->address;
736f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
737f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
738f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ClassObject* throwable =
739f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                dvmDexGetResolvedClass(pDvmDex, handler->typeIdx);
740f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (throwable == NULL) {
741f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                /*
742f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * TODO: this behaves badly if we run off the stack
743f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * while trying to throw an exception.  The problem is
744f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * that, if we're in a class loaded by a class loader,
745f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * the call to dvmResolveClass has to ask the class
746f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * loader for help resolving any previously-unresolved
747f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * classes.  If this particular class loader hasn't
748f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * resolved StackOverflowError, it will call into
749f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * interpreted code, and blow up.
750f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 *
751f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * We currently replace the previous exception with
752f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * the StackOverflowError, which means they won't be
753f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * catching it *unless* they explicitly catch
754f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * StackOverflowError, in which case we'll be unable
755f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * to resolve the class referred to by the "catch"
756f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * block.
757f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 *
758f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * We end up getting a huge pile of warnings if we do
759f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * a simple synthetic test, because this method gets
760f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * called on every stack frame up the tree, and it
761f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * fails every time.
762f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 *
763f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * This eventually bails out, effectively becoming an
764f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * uncatchable exception, so other than the flurry of
765f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * warnings it's not really a problem.  Still, we could
766f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * probably handle this better.
767f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 */
768f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                throwable = dvmResolveClass(method->clazz, handler->typeIdx,
769f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    true);
770f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (throwable == NULL) {
771f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    /*
772f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                     * We couldn't find the exception they wanted in
773f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                     * our class files (or, perhaps, the stack blew up
774f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                     * while we were querying a class loader). Cough
775f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                     * up a warning, then move on to the next entry.
776f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                     * Keep the exception status clear.
777f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                     */
778f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    LOGW("Could not resolve class ref'ed in exception "
779f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            "catch list (class index %d, exception %s)\n",
780f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            handler->typeIdx,
781f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            (self->exception != NULL) ?
782f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            self->exception->clazz->descriptor : "(none)");
783f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    dvmClearException(self);
784f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    continue;
785f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
786f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
787f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
788f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            //LOGD("ADDR MATCH, check %s instanceof %s\n",
789f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            //    excepClass->descriptor, pEntry->excepClass->descriptor);
790f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
791f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (dvmInstanceof(excepClass, throwable)) {
792f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                LOGV("Match on catch block at 0x%02x in %s.%s for %s\n",
793f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        relPc, method->clazz->descriptor,
794f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        method->name, excepClass->descriptor);
795f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                return handler->address;
796f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
797f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
798f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
799f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
800f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    LOGV("No matching catch block at 0x%02x in %s for %s\n",
801f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        relPc, method->name, excepClass->descriptor);
802f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return -1;
803f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
804f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
805f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
806f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Find a matching "catch" block.  "pc" is the relative PC within the
807f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * current method, indicating the offset from the start in 16-bit units.
808f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
809f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Returns the offset to the catch block, or -1 if we run up against a
810f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * break frame without finding anything.
811f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
812f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The class resolution stuff we have to do while evaluating the "catch"
813f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * blocks could cause an exception.  The caller should clear the exception
814f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * before calling here and restore it after.
815f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
816f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Sets *newFrame to the frame pointer of the frame with the catch block.
817f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * If "scanOnly" is false, self->curFrame is also set to this value.
818f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
819f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectint dvmFindCatchBlock(Thread* self, int relPc, Object* exception,
820f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    bool scanOnly, void** newFrame)
821f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
822f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    void* fp = self->curFrame;
823f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int catchAddr = -1;
824f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
825f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(!dvmCheckException(self));
826f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
827f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    while (true) {
828f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        StackSaveArea* saveArea = SAVEAREA_FROM_FP(fp);
829f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        catchAddr = findCatchInMethod(self, saveArea->method, relPc,
830f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        exception->clazz);
831f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (catchAddr >= 0)
832f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            break;
833f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
834f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
835f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Normally we'd check for ACC_SYNCHRONIZED methods and unlock
836f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * them as we unroll.  Dalvik uses what amount to generated
837f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * "finally" blocks to take care of this for us.
838f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
839f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
840f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* output method profiling info */
841f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (!scanOnly) {
842f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            TRACE_METHOD_UNROLL(self, saveArea->method);
843f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
844f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
845f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
846f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Move up one frame.  If the next thing up is a break frame,
847f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * break out now so we're left unrolled to the last method frame.
848f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * We need to point there so we can roll up the JNI local refs
849f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * if this was a native method.
850f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
851f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        assert(saveArea->prevFrame != NULL);
852f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (dvmIsBreakFrame(saveArea->prevFrame)) {
853f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (!scanOnly)
854f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                break;      // bail with catchAddr == -1
855f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
856f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
857f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * We're scanning for the debugger.  It needs to know if this
858f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * exception is going to be caught or not, and we need to figure
859f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * out if it will be caught *ever* not just between the current
860f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * position and the next break frame.  We can't tell what native
861f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * code is going to do, so we assume it never catches exceptions.
862f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             *
863f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * Start by finding an interpreted code frame.
864f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
865f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            fp = saveArea->prevFrame;           // this is the break frame
866f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            saveArea = SAVEAREA_FROM_FP(fp);
867f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            fp = saveArea->prevFrame;           // this may be a good one
868f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            while (fp != NULL) {
869f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (!dvmIsBreakFrame(fp)) {
870f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    saveArea = SAVEAREA_FROM_FP(fp);
871f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    if (!dvmIsNativeMethod(saveArea->method))
872f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        break;
873f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
874f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
875f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                fp = SAVEAREA_FROM_FP(fp)->prevFrame;
876f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
877f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (fp == NULL)
878f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                break;      // bail with catchAddr == -1
879f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
880f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
881f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * Now fp points to the "good" frame.  When the interp code
882f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * invoked the native code, it saved a copy of its current PC
883f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * into xtra.currentPc.  Pull it out of there.
884f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
885f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            relPc =
886f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                saveArea->xtra.currentPc - SAVEAREA_FROM_FP(fp)->method->insns;
887f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
888f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            fp = saveArea->prevFrame;
889f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
890f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /* savedPc in was-current frame goes with method in now-current */
891f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            relPc = saveArea->savedPc - SAVEAREA_FROM_FP(fp)->method->insns;
892f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
893f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
894f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
895f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (!scanOnly)
896f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        self->curFrame = fp;
897f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
898f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
899f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * The class resolution in findCatchInMethod() could cause an exception.
900f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Clear it to be safe.
901f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
902f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    self->exception = NULL;
903f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
904f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    *newFrame = fp;
905f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return catchAddr;
906f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
907f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
908f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
909f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We have to carry the exception's stack trace around, but in many cases
910f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * it will never be examined.  It makes sense to keep it in a compact,
911f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * VM-specific object, rather than an array of Objects with strings.
912f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
913f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Pass in the thread whose stack we're interested in.  If "thread" is
914f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * not self, the thread must be suspended.  This implies that the thread
915f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * list lock is held, which means we can't allocate objects or we risk
916f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * jamming the GC.  So, we allow this function to return different formats.
917f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * (This shouldn't be called directly -- see the inline functions in the
918f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * header file.)
919f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
920f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * If "wantObject" is true, this returns a newly-allocated Object, which is
921f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * presently an array of integers, but could become something else in the
922f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * future.  If "wantObject" is false, return plain malloc data.
923f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
924f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * NOTE: if we support class unloading, we will need to scan the class
925f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * object references out of these arrays.
926f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
927f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid* dvmFillInStackTraceInternal(Thread* thread, bool wantObject, int* pCount)
928f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
929f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    ArrayObject* stackData = NULL;
930f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int* simpleData = NULL;
931f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    void* fp;
932f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    void* startFp;
933f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int stackDepth;
934f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int* intPtr;
935f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
936f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (pCount != NULL)
937f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        *pCount = 0;
938f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    fp = thread->curFrame;
939f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
940f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(thread == dvmThreadSelf() || dvmIsSuspended(thread));
941f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
942f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
943f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * We're looking at a stack frame for code running below a Throwable
944f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * constructor.  We want to remove the Throwable methods and the
945f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * superclass initializations so the user doesn't see them when they
946f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * read the stack dump.
947f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
948f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * TODO: this just scrapes off the top layers of Throwable.  Might not do
949f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * the right thing if we create an exception object or cause a VM
950f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * exception while in a Throwable method.
951f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
952f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    while (fp != NULL) {
953f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        const StackSaveArea* saveArea = SAVEAREA_FROM_FP(fp);
954f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        const Method* method = saveArea->method;
955f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
956f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (dvmIsBreakFrame(fp))
957f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            break;
958f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (!dvmInstanceof(method->clazz, gDvm.classJavaLangThrowable))
959f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            break;
960f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //LOGD("EXCEP: ignoring %s.%s\n",
961f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //         method->clazz->descriptor, method->name);
962f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        fp = saveArea->prevFrame;
963f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
964f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    startFp = fp;
965f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
966f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
967f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Compute the stack depth.
968f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
969f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    stackDepth = 0;
970f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    while (fp != NULL) {
971f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        const StackSaveArea* saveArea = SAVEAREA_FROM_FP(fp);
972f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
973f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (!dvmIsBreakFrame(fp))
974f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            stackDepth++;
975f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
976f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        assert(fp != saveArea->prevFrame);
977f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        fp = saveArea->prevFrame;
978f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
979f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    //LOGD("EXCEP: stack depth is %d\n", stackDepth);
980f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
981f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (!stackDepth)
982f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
983f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
984f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
985f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * We need to store a pointer to the Method and the program counter.
986f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * We have 4-byte pointers, so we use '[I'.
987f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
988f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (wantObject) {
989f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        assert(sizeof(Method*) == 4);
990f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        stackData = dvmAllocPrimitiveArray('I', stackDepth*2, ALLOC_DEFAULT);
991f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (stackData == NULL) {
992f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            assert(dvmCheckException(dvmThreadSelf()));
993f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            goto bail;
994f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
995f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        intPtr = (int*) stackData->contents;
996f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } else {
997f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* array of ints; first entry is stack depth */
998f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        assert(sizeof(Method*) == sizeof(int));
999f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        simpleData = (int*) malloc(sizeof(int) * stackDepth*2);
1000f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (simpleData == NULL)
1001f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            goto bail;
1002f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1003f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        assert(pCount != NULL);
1004f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        intPtr = simpleData;
1005f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1006f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (pCount != NULL)
1007f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        *pCount = stackDepth;
1008f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1009f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    fp = startFp;
1010f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    while (fp != NULL) {
1011f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        const StackSaveArea* saveArea = SAVEAREA_FROM_FP(fp);
1012f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        const Method* method = saveArea->method;
1013f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1014f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (!dvmIsBreakFrame(fp)) {
1015f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            //LOGD("EXCEP keeping %s.%s\n", method->clazz->descriptor,
1016f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            //         method->name);
1017f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1018f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            *intPtr++ = (int) method;
1019f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (dvmIsNativeMethod(method)) {
1020f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                *intPtr++ = 0;      /* no saved PC for native methods */
1021f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
1022f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                assert(saveArea->xtra.currentPc >= method->insns &&
1023f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        saveArea->xtra.currentPc <
1024f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        method->insns + dvmGetMethodInsnsSize(method));
1025f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                *intPtr++ = (int) (saveArea->xtra.currentPc - method->insns);
1026f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1027f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1028f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            stackDepth--;       // for verification
1029f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1030f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1031f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        assert(fp != saveArea->prevFrame);
1032f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        fp = saveArea->prevFrame;
1033f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1034f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(stackDepth == 0);
1035f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1036f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbail:
1037f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (wantObject) {
1038f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmReleaseTrackedAlloc((Object*) stackData, dvmThreadSelf());
1039f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return stackData;
1040f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } else {
1041f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return simpleData;
1042f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1043f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
1044f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1045f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1046f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
1047f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Given an Object previously created by dvmFillInStackTrace(), use the
1048f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * contents of the saved stack trace to generate an array of
1049f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * java/lang/StackTraceElement objects.
1050f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
1051f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The returned array is not added to the "local refs" list.
1052f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
1053f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectArrayObject* dvmGetStackTrace(const Object* ostackData)
1054f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
1055f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    const ArrayObject* stackData = (const ArrayObject*) ostackData;
1056f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    const int* intVals;
1057f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int i, stackSize;
1058f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1059f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    stackSize = stackData->length / 2;
1060f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    intVals = (const int*) stackData->contents;
1061f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return dvmGetStackTraceRaw(intVals, stackSize);
1062f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
1063f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1064f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
1065f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Generate an array of StackTraceElement objects from the raw integer
1066f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * data encoded by dvmFillInStackTrace().
1067f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
1068f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * "intVals" points to the first {method,pc} pair.
1069f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
1070f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The returned array is not added to the "local refs" list.
1071f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
1072f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectArrayObject* dvmGetStackTraceRaw(const int* intVals, int stackDepth)
1073f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
1074f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    ArrayObject* steArray = NULL;
1075f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    Object** stePtr;
1076f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int i;
1077f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1078f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* init this if we haven't yet */
1079f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (!dvmIsClassInitialized(gDvm.classJavaLangStackTraceElement))
1080f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmInitClass(gDvm.classJavaLangStackTraceElement);
1081f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1082f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* allocate a StackTraceElement array */
1083f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    steArray = dvmAllocArray(gDvm.classJavaLangStackTraceElementArray,
1084f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    stackDepth, kObjectArrayRefWidth, ALLOC_DEFAULT);
1085f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (steArray == NULL)
1086f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
1087f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    stePtr = (Object**) steArray->contents;
1088f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1089f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
1090f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Allocate and initialize a StackTraceElement for each stack frame.
1091f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * We use the standard constructor to configure the object.
1092f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
1093f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    for (i = 0; i < stackDepth; i++) {
1094f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Object* ste;
1095f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Method* meth;
1096f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        StringObject* className;
1097f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        StringObject* methodName;
1098f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        StringObject* fileName;
1099f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int lineNumber, pc;
1100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        const char* sourceFile;
1101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        char* dotName;
1102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        ste = dvmAllocObject(gDvm.classJavaLangStackTraceElement,ALLOC_DEFAULT);
1104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (ste == NULL)
1105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            goto bail;
1106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        meth = (Method*) *intVals++;
1108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        pc = *intVals++;
1109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (pc == -1)      // broken top frame?
1111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            lineNumber = 0;
1112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        else
1113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            lineNumber = dvmLineNumFromPC(meth, pc);
1114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dotName = dvmDescriptorToDot(meth->clazz->descriptor);
1116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        className = dvmCreateStringFromCstr(dotName, ALLOC_DEFAULT);
1117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        free(dotName);
1118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        methodName = dvmCreateStringFromCstr(meth->name, ALLOC_DEFAULT);
1120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        sourceFile = dvmGetMethodSourceFile(meth);
1121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (sourceFile != NULL)
1122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            fileName = dvmCreateStringFromCstr(sourceFile, ALLOC_DEFAULT);
1123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        else
1124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            fileName = NULL;
1125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
1127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Invoke:
1128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         *  public StackTraceElement(String declaringClass, String methodName,
1129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         *      String fileName, int lineNumber)
1130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * (where lineNumber==-2 means "native")
1131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
1132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        JValue unused;
1133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmCallMethod(dvmThreadSelf(), gDvm.methJavaLangStackTraceElement_init,
1134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ste, &unused, className, methodName, fileName, lineNumber);
1135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmReleaseTrackedAlloc(ste, NULL);
1137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmReleaseTrackedAlloc((Object*) className, NULL);
1138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmReleaseTrackedAlloc((Object*) methodName, NULL);
1139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmReleaseTrackedAlloc((Object*) fileName, NULL);
1140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (dvmCheckException(dvmThreadSelf()))
1142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            goto bail;
1143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        *stePtr++ = ste;
1145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbail:
1148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmReleaseTrackedAlloc((Object*) steArray, NULL);
1149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return steArray;
1150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
1151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
1153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Dump the contents of a raw stack trace to the log.
1154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
1155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmLogRawStackTrace(const int* intVals, int stackDepth)
1156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
1157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int i;
1158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
1160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Run through the array of stack frame data.
1161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
1162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    for (i = 0; i < stackDepth; i++) {
1163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Method* meth;
1164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int lineNumber, pc;
1165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        const char* sourceFile;
1166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        char* dotName;
1167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        meth = (Method*) *intVals++;
1169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        pc = *intVals++;
1170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (pc == -1)      // broken top frame?
1172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            lineNumber = 0;
1173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        else
1174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            lineNumber = dvmLineNumFromPC(meth, pc);
1175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // probably don't need to do this, but it looks nicer
1177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dotName = dvmDescriptorToDot(meth->clazz->descriptor);
1178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (dvmIsNativeMethod(meth)) {
1180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            LOGI("\tat %s.%s(Native Method)\n", dotName, meth->name);
1181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
1182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            LOGI("\tat %s.%s(%s:%d)\n",
1183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                dotName, meth->name, dvmGetMethodSourceFile(meth),
1184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                dvmLineNumFromPC(meth, pc));
1185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        free(dotName);
1188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        sourceFile = dvmGetMethodSourceFile(meth);
1190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
1192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
1194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Print the direct stack trace of the given exception to the log.
1195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
1196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void logStackTraceOf(Object* exception)
1197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
1198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    const ArrayObject* stackData;
1199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    StringObject* messageStr;
1200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int stackSize;
1201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    const int* intVals;
1202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    messageStr = (StringObject*) dvmGetFieldObject(exception,
1204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    gDvm.offJavaLangThrowable_message);
1205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (messageStr != NULL) {
1206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        char* cp = dvmCreateCstrFromString(messageStr);
1207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGI("%s: %s\n", exception->clazz->descriptor, cp);
1208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        free(cp);
1209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } else {
1210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGI("%s:\n", exception->clazz->descriptor);
1211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    stackData = (const ArrayObject*) dvmGetFieldObject(exception,
1214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    gDvm.offJavaLangThrowable_stackState);
1215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (stackData == NULL) {
1216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGI("  (no stack trace data found)\n");
1217f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return;
1218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1220f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    stackSize = stackData->length / 2;
1221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    intVals = (const int*) stackData->contents;
1222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmLogRawStackTrace(intVals, stackSize);
1224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
1225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
1227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Print the stack trace of the current thread's exception, as well as
1228f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * the stack traces of any chained exceptions, to the log. We extract
1229f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * the stored stack trace and process it internally instead of calling
1230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * interpreted code.
1231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
1232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmLogExceptionStackTrace(void)
1233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
1234f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    Object* exception = dvmThreadSelf()->exception;
1235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    Object* cause;
1236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (exception == NULL) {
1238f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGW("tried to log a null exception?\n");
1239f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return;
1240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    for (;;) {
1243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        logStackTraceOf(exception);
1244686e1e23324f1c1f358f29f13f23e57b41c00eaaAndy McFadden        cause = dvmGetExceptionCause(exception);
1245686e1e23324f1c1f358f29f13f23e57b41c00eaaAndy McFadden        if (cause == NULL) {
1246f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            break;
1247f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1248f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGI("Caused by:\n");
1249f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        exception = cause;
1250f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1251f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
1252f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1253