Stack.cpp revision b3667a19f5c573b7785876979af4781292d27327
1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 * Stacks and their uses (e.g. native --> interpreted method calls).
19 *
20 * See the majestic ASCII art in Stack.h.
21 */
22#include "Dalvik.h"
23#include "jni.h"
24
25#include <stdlib.h>
26#include <stdarg.h>
27
28#ifdef HAVE_ANDROID_OS
29#include <corkscrew/backtrace.h>
30#endif
31
32/*
33 * Initialize the interpreter stack in a new thread.
34 *
35 * Currently this doesn't do much, since we don't need to zero out the
36 * stack (and we really don't want to if it was created with mmap).
37 */
38bool dvmInitInterpStack(Thread* thread, int stackSize)
39{
40    assert(thread->interpStackStart != NULL);
41
42    assert(thread->interpSave.curFrame == NULL);
43
44    return true;
45}
46
47/*
48 * We're calling an interpreted method from an internal VM function or
49 * via reflection.
50 *
51 * Push a frame for an interpreted method onto the stack.  This is only
52 * used when calling into interpreted code from native code.  (The
53 * interpreter does its own stack frame manipulation for interp-->interp
54 * calls.)
55 *
56 * The size we need to reserve is the sum of parameters, local variables,
57 * saved goodies, and outbound parameters.
58 *
59 * We start by inserting a "break" frame, which ensures that the interpreter
60 * hands control back to us after the function we call returns or an
61 * uncaught exception is thrown.
62 */
63static bool dvmPushInterpFrame(Thread* self, const Method* method)
64{
65    StackSaveArea* saveBlock;
66    StackSaveArea* breakSaveBlock;
67    int stackReq;
68    u1* stackPtr;
69
70    assert(!dvmIsNativeMethod(method));
71    assert(!dvmIsAbstractMethod(method));
72
73    stackReq = method->registersSize * 4        // params + locals
74                + sizeof(StackSaveArea) * 2     // break frame + regular frame
75                + method->outsSize * 4;         // args to other methods
76
77    if (self->interpSave.curFrame != NULL)
78        stackPtr = (u1*) SAVEAREA_FROM_FP(self->interpSave.curFrame);
79    else
80        stackPtr = self->interpStackStart;
81
82    if (stackPtr - stackReq < self->interpStackEnd) {
83        /* not enough space */
84        ALOGW("Stack overflow on call to interp "
85             "(req=%d top=%p cur=%p size=%d %s.%s)",
86            stackReq, self->interpStackStart, self->interpSave.curFrame,
87            self->interpStackSize, method->clazz->descriptor, method->name);
88        dvmHandleStackOverflow(self, method);
89        assert(dvmCheckException(self));
90        return false;
91    }
92
93    /*
94     * Shift the stack pointer down, leaving space for the function's
95     * args/registers and save area.
96     */
97    stackPtr -= sizeof(StackSaveArea);
98    breakSaveBlock = (StackSaveArea*)stackPtr;
99    stackPtr -= method->registersSize * 4 + sizeof(StackSaveArea);
100    saveBlock = (StackSaveArea*) stackPtr;
101
102#if !defined(NDEBUG) && !defined(PAD_SAVE_AREA)
103    /* debug -- memset the new stack, unless we want valgrind's help */
104    memset(stackPtr - (method->outsSize*4), 0xaf, stackReq);
105#endif
106#ifdef EASY_GDB
107    breakSaveBlock->prevSave =
108       (StackSaveArea*)FP_FROM_SAVEAREA(self->interpSave.curFrame);
109    saveBlock->prevSave = breakSaveBlock;
110#endif
111
112    breakSaveBlock->prevFrame = self->interpSave.curFrame;
113    breakSaveBlock->savedPc = NULL;             // not required
114    breakSaveBlock->xtra.localRefCookie = 0;    // not required
115    breakSaveBlock->method = NULL;
116    saveBlock->prevFrame = FP_FROM_SAVEAREA(breakSaveBlock);
117    saveBlock->savedPc = NULL;                  // not required
118    saveBlock->xtra.currentPc = NULL;           // not required?
119    saveBlock->method = method;
120
121    LOGVV("PUSH frame: old=%p new=%p (size=%d)",
122        self->interpSave.curFrame, FP_FROM_SAVEAREA(saveBlock),
123        (u1*)self->interpSave.curFrame - (u1*)FP_FROM_SAVEAREA(saveBlock));
124
125    self->interpSave.curFrame = FP_FROM_SAVEAREA(saveBlock);
126
127    return true;
128}
129
130/*
131 * We're calling a JNI native method from an internal VM fuction or
132 * via reflection.  This is also used to create the "fake" native-method
133 * frames at the top of the interpreted stack.
134 *
135 * This actually pushes two frames; the first is a "break" frame.
136 *
137 * The top frame has additional space for JNI local reference tracking.
138 */
139bool dvmPushJNIFrame(Thread* self, const Method* method)
140{
141    StackSaveArea* saveBlock;
142    StackSaveArea* breakSaveBlock;
143    int stackReq;
144    u1* stackPtr;
145
146    assert(dvmIsNativeMethod(method));
147
148    stackReq = method->registersSize * 4        // params only
149                + sizeof(StackSaveArea) * 2;    // break frame + regular frame
150
151    if (self->interpSave.curFrame != NULL)
152        stackPtr = (u1*) SAVEAREA_FROM_FP(self->interpSave.curFrame);
153    else
154        stackPtr = self->interpStackStart;
155
156    if (stackPtr - stackReq < self->interpStackEnd) {
157        /* not enough space */
158        ALOGW("Stack overflow on call to native "
159             "(req=%d top=%p cur=%p size=%d '%s')",
160            stackReq, self->interpStackStart, self->interpSave.curFrame,
161            self->interpStackSize, method->name);
162        dvmHandleStackOverflow(self, method);
163        assert(dvmCheckException(self));
164        return false;
165    }
166
167    /*
168     * Shift the stack pointer down, leaving space for just the stack save
169     * area for the break frame, then shift down farther for the full frame.
170     * We leave space for the method args, which are copied in later.
171     */
172    stackPtr -= sizeof(StackSaveArea);
173    breakSaveBlock = (StackSaveArea*)stackPtr;
174    stackPtr -= method->registersSize * 4 + sizeof(StackSaveArea);
175    saveBlock = (StackSaveArea*) stackPtr;
176
177#if !defined(NDEBUG) && !defined(PAD_SAVE_AREA)
178    /* debug -- memset the new stack */
179    memset(stackPtr, 0xaf, stackReq);
180#endif
181#ifdef EASY_GDB
182    if (self->interpSave.curFrame == NULL)
183        breakSaveBlock->prevSave = NULL;
184    else {
185        void* fp = FP_FROM_SAVEAREA(self->interpSave.curFrame);
186        breakSaveBlock->prevSave = (StackSaveArea*)fp;
187    }
188    saveBlock->prevSave = breakSaveBlock;
189#endif
190
191    breakSaveBlock->prevFrame = self->interpSave.curFrame;
192    breakSaveBlock->savedPc = NULL;             // not required
193    breakSaveBlock->xtra.localRefCookie = 0;    // not required
194    breakSaveBlock->method = NULL;
195    saveBlock->prevFrame = FP_FROM_SAVEAREA(breakSaveBlock);
196    saveBlock->savedPc = NULL;                  // not required
197    saveBlock->xtra.localRefCookie = self->jniLocalRefTable.segmentState.all;
198    saveBlock->method = method;
199
200    LOGVV("PUSH JNI frame: old=%p new=%p (size=%d)",
201        self->interpSave.curFrame, FP_FROM_SAVEAREA(saveBlock),
202        (u1*)self->interpSave.curFrame - (u1*)FP_FROM_SAVEAREA(saveBlock));
203
204    self->interpSave.curFrame = FP_FROM_SAVEAREA(saveBlock);
205
206    return true;
207}
208
209/*
210 * This is used by the JNI PushLocalFrame call.  We push a new frame onto
211 * the stack that has no ins, outs, or locals, and no break frame above it.
212 * It's strictly used for tracking JNI local refs, and will be popped off
213 * by dvmPopFrame if it's not removed explicitly.
214 */
215bool dvmPushLocalFrame(Thread* self, const Method* method)
216{
217    StackSaveArea* saveBlock;
218    int stackReq;
219    u1* stackPtr;
220
221    assert(dvmIsNativeMethod(method));
222
223    stackReq = sizeof(StackSaveArea);       // regular frame
224
225    assert(self->interpSave.curFrame != NULL);
226    stackPtr = (u1*) SAVEAREA_FROM_FP(self->interpSave.curFrame);
227
228    if (stackPtr - stackReq < self->interpStackEnd) {
229        /* not enough space; let JNI throw the exception */
230        ALOGW("Stack overflow on PushLocal "
231             "(req=%d top=%p cur=%p size=%d '%s')",
232            stackReq, self->interpStackStart, self->interpSave.curFrame,
233            self->interpStackSize, method->name);
234        dvmHandleStackOverflow(self, method);
235        assert(dvmCheckException(self));
236        return false;
237    }
238
239    /*
240     * Shift the stack pointer down, leaving space for just the stack save
241     * area for the break frame, then shift down farther for the full frame.
242     */
243    stackPtr -= sizeof(StackSaveArea);
244    saveBlock = (StackSaveArea*) stackPtr;
245
246#if !defined(NDEBUG) && !defined(PAD_SAVE_AREA)
247    /* debug -- memset the new stack */
248    memset(stackPtr, 0xaf, stackReq);
249#endif
250#ifdef EASY_GDB
251    saveBlock->prevSave =
252        (StackSaveArea*)FP_FROM_SAVEAREA(self->interpSave.curFrame);
253#endif
254
255    saveBlock->prevFrame = self->interpSave.curFrame;
256    saveBlock->savedPc = NULL;                  // not required
257    saveBlock->xtra.localRefCookie = self->jniLocalRefTable.segmentState.all;
258    saveBlock->method = method;
259
260    LOGVV("PUSH JNI local frame: old=%p new=%p (size=%d)",
261        self->interpSave.curFrame, FP_FROM_SAVEAREA(saveBlock),
262        (u1*)self->interpSave.curFrame - (u1*)FP_FROM_SAVEAREA(saveBlock));
263
264    self->interpSave.curFrame = FP_FROM_SAVEAREA(saveBlock);
265
266    return true;
267}
268
269/*
270 * Pop one frame pushed on by JNI PushLocalFrame.
271 *
272 * If we've gone too far, the previous frame is either a break frame or
273 * an interpreted frame.  Either way, the method pointer won't match.
274 */
275bool dvmPopLocalFrame(Thread* self)
276{
277    StackSaveArea* saveBlock = SAVEAREA_FROM_FP(self->interpSave.curFrame);
278
279    assert(!dvmIsBreakFrame((u4*)self->interpSave.curFrame));
280    if (saveBlock->method != SAVEAREA_FROM_FP(saveBlock->prevFrame)->method) {
281        /*
282         * The previous frame doesn't have the same method pointer -- we've
283         * been asked to pop too much.
284         */
285        assert(dvmIsBreakFrame((u4*)saveBlock->prevFrame) ||
286               !dvmIsNativeMethod(
287                       SAVEAREA_FROM_FP(saveBlock->prevFrame)->method));
288        return false;
289    }
290
291    LOGVV("POP JNI local frame: removing %s, now %s",
292        saveBlock->method->name,
293        SAVEAREA_FROM_FP(saveBlock->prevFrame)->method->name);
294    dvmPopJniLocals(self, saveBlock);
295    self->interpSave.curFrame = saveBlock->prevFrame;
296
297    return true;
298}
299
300/*
301 * Pop a frame we added.  There should be one method frame and one break
302 * frame.
303 *
304 * If JNI Push/PopLocalFrame calls were mismatched, we might end up
305 * popping multiple method frames before we find the break.
306 *
307 * Returns "false" if there was no frame to pop.
308 */
309static bool dvmPopFrame(Thread* self)
310{
311    StackSaveArea* saveBlock;
312
313    if (self->interpSave.curFrame == NULL)
314        return false;
315
316    saveBlock = SAVEAREA_FROM_FP(self->interpSave.curFrame);
317    assert(!dvmIsBreakFrame((u4*)self->interpSave.curFrame));
318
319    /*
320     * Remove everything up to the break frame.  If this was a call into
321     * native code, pop the JNI local references table.
322     */
323    while (saveBlock->prevFrame != NULL && saveBlock->method != NULL) {
324        /* probably a native->native JNI call */
325
326        if (dvmIsNativeMethod(saveBlock->method)) {
327            LOGVV("Popping JNI stack frame for %s.%s%s",
328                saveBlock->method->clazz->descriptor,
329                saveBlock->method->name,
330                (SAVEAREA_FROM_FP(saveBlock->prevFrame)->method == NULL) ?
331                "" : " (JNI local)");
332            dvmPopJniLocals(self, saveBlock);
333        }
334
335        saveBlock = SAVEAREA_FROM_FP(saveBlock->prevFrame);
336    }
337    if (saveBlock->method != NULL) {
338        ALOGE("PopFrame missed the break");
339        assert(false);
340        dvmAbort();     // stack trashed -- nowhere to go in this thread
341    }
342
343    LOGVV("POP frame: cur=%p new=%p",
344        self->interpSave.curFrame, saveBlock->prevFrame);
345
346    self->interpSave.curFrame = saveBlock->prevFrame;
347    return true;
348}
349
350/*
351 * Common code for dvmCallMethodV/A and dvmInvokeMethod.
352 *
353 * Pushes a call frame on, advancing self->interpSave.curFrame.
354 */
355static ClassObject* callPrep(Thread* self, const Method* method, Object* obj,
356    bool checkAccess)
357{
358    ClassObject* clazz;
359
360#ifndef NDEBUG
361    if (self->status != THREAD_RUNNING) {
362        ALOGW("threadid=%d: status=%d on call to %s.%s -",
363            self->threadId, self->status,
364            method->clazz->descriptor, method->name);
365    }
366#endif
367
368    assert(self != NULL);
369    assert(method != NULL);
370
371    if (obj != NULL)
372        clazz = obj->clazz;
373    else
374        clazz = method->clazz;
375
376    IF_LOGVV() {
377        char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
378        LOGVV("thread=%d native code calling %s.%s %s", self->threadId,
379            clazz->descriptor, method->name, desc);
380        free(desc);
381    }
382
383    if (checkAccess) {
384        /* needed for java.lang.reflect.Method.invoke */
385        if (!dvmCheckMethodAccess(dvmGetCaller2Class(self->interpSave.curFrame),
386                method))
387        {
388            /* note this throws IAException, not IAError */
389            dvmThrowIllegalAccessException("access to method denied");
390            return NULL;
391        }
392    }
393
394    /*
395     * Push a call frame on.  If there isn't enough room for ins, locals,
396     * outs, and the saved state, it will throw an exception.
397     *
398     * This updates self->interpSave.curFrame.
399     */
400    if (dvmIsNativeMethod(method)) {
401        /* native code calling native code the hard way */
402        if (!dvmPushJNIFrame(self, method)) {
403            assert(dvmCheckException(self));
404            return NULL;
405        }
406    } else {
407        /* native code calling interpreted code */
408        if (!dvmPushInterpFrame(self, method)) {
409            assert(dvmCheckException(self));
410            return NULL;
411        }
412    }
413
414    return clazz;
415}
416
417/*
418 * Issue a method call.
419 *
420 * Pass in NULL for "obj" on calls to static methods.
421 *
422 * (Note this can't be inlined because it takes a variable number of args.)
423 */
424void dvmCallMethod(Thread* self, const Method* method, Object* obj,
425    JValue* pResult, ...)
426{
427    va_list args;
428    va_start(args, pResult);
429    dvmCallMethodV(self, method, obj, false, pResult, args);
430    va_end(args);
431}
432
433/*
434 * Issue a method call with a variable number of arguments.  We process
435 * the contents of "args" by scanning the method signature.
436 *
437 * Pass in NULL for "obj" on calls to static methods.
438 *
439 * We don't need to take the class as an argument because, in Dalvik,
440 * we don't need to worry about static synchronized methods.
441 */
442void dvmCallMethodV(Thread* self, const Method* method, Object* obj,
443    bool fromJni, JValue* pResult, va_list args)
444{
445    const char* desc = &(method->shorty[1]); // [0] is the return type.
446    int verifyCount = 0;
447    ClassObject* clazz;
448    u4* ins;
449
450    clazz = callPrep(self, method, obj, false);
451    if (clazz == NULL)
452        return;
453
454    /* "ins" for new frame start at frame pointer plus locals */
455    ins = ((u4*)self->interpSave.curFrame) +
456           (method->registersSize - method->insSize);
457
458    //ALOGD("  FP is %p, INs live at >= %p", self->interpSave.curFrame, ins);
459
460    /* put "this" pointer into in0 if appropriate */
461    if (!dvmIsStaticMethod(method)) {
462#ifdef WITH_EXTRA_OBJECT_VALIDATION
463        assert(obj != NULL && dvmIsHeapAddress(obj));
464#endif
465        *ins++ = (u4) obj;
466        verifyCount++;
467    }
468
469    while (*desc != '\0') {
470        switch (*(desc++)) {
471            case 'D': case 'J': {
472                u8 val = va_arg(args, u8);
473                memcpy(ins, &val, 8);       // EABI prevents direct store
474                ins += 2;
475                verifyCount += 2;
476                break;
477            }
478            case 'F': {
479                /* floats were normalized to doubles; convert back */
480                float f = (float) va_arg(args, double);
481                *ins++ = dvmFloatToU4(f);
482                verifyCount++;
483                break;
484            }
485            case 'L': {     /* 'shorty' descr uses L for all refs, incl array */
486                void* arg = va_arg(args, void*);
487                assert(obj == NULL || dvmIsHeapAddress(obj));
488                jobject argObj = reinterpret_cast<jobject>(arg);
489                if (fromJni)
490                    *ins++ = (u4) dvmDecodeIndirectRef(self, argObj);
491                else
492                    *ins++ = (u4) argObj;
493                verifyCount++;
494                break;
495            }
496            default: {
497                /* Z B C S I -- all passed as 32-bit integers */
498                *ins++ = va_arg(args, u4);
499                verifyCount++;
500                break;
501            }
502        }
503    }
504
505#ifndef NDEBUG
506    if (verifyCount != method->insSize) {
507        ALOGE("Got vfycount=%d insSize=%d for %s.%s", verifyCount,
508            method->insSize, clazz->descriptor, method->name);
509        assert(false);
510        goto bail;
511    }
512#endif
513
514    //dvmDumpThreadStack(dvmThreadSelf());
515
516    if (dvmIsNativeMethod(method)) {
517        TRACE_METHOD_ENTER(self, method);
518        /*
519         * Because we leave no space for local variables, "curFrame" points
520         * directly at the method arguments.
521         */
522        (*method->nativeFunc)((u4*)self->interpSave.curFrame, pResult,
523                              method, self);
524        TRACE_METHOD_EXIT(self, method);
525    } else {
526        dvmInterpret(self, method, pResult);
527    }
528
529#ifndef NDEBUG
530bail:
531#endif
532    dvmPopFrame(self);
533}
534
535/*
536 * Issue a method call with arguments provided in an array.  We process
537 * the contents of "args" by scanning the method signature.
538 *
539 * The values were likely placed into an uninitialized jvalue array using
540 * the field specifiers, which means that sub-32-bit fields (e.g. short,
541 * boolean) may not have 32 or 64 bits of valid data.  This is different
542 * from the varargs invocation where the C compiler does a widening
543 * conversion when calling a function.  As a result, we have to be a
544 * little more precise when pulling stuff out.
545 *
546 * "args" may be NULL if the method has no arguments.
547 */
548void dvmCallMethodA(Thread* self, const Method* method, Object* obj,
549    bool fromJni, JValue* pResult, const jvalue* args)
550{
551    const char* desc = &(method->shorty[1]); // [0] is the return type.
552    int verifyCount = 0;
553    ClassObject* clazz;
554    u4* ins;
555
556    clazz = callPrep(self, method, obj, false);
557    if (clazz == NULL)
558        return;
559
560    /* "ins" for new frame start at frame pointer plus locals */
561    ins = ((u4*)self->interpSave.curFrame) +
562        (method->registersSize - method->insSize);
563
564    /* put "this" pointer into in0 if appropriate */
565    if (!dvmIsStaticMethod(method)) {
566        assert(obj != NULL);
567        *ins++ = (u4) obj;              /* obj is a "real" ref */
568        verifyCount++;
569    }
570
571    while (*desc != '\0') {
572        switch (*desc++) {
573        case 'D':                       /* 64-bit quantity; have to use */
574        case 'J':                       /*  memcpy() in case of mis-alignment */
575            memcpy(ins, &args->j, 8);
576            ins += 2;
577            verifyCount++;              /* this needs an extra push */
578            break;
579        case 'L':                       /* includes array refs */
580            if (fromJni)
581                *ins++ = (u4) dvmDecodeIndirectRef(self, args->l);
582            else
583                *ins++ = (u4) args->l;
584            break;
585        case 'F':
586        case 'I':
587            *ins++ = args->i;           /* full 32 bits */
588            break;
589        case 'S':
590            *ins++ = args->s;           /* 16 bits, sign-extended */
591            break;
592        case 'C':
593            *ins++ = args->c;           /* 16 bits, unsigned */
594            break;
595        case 'B':
596            *ins++ = args->b;           /* 8 bits, sign-extended */
597            break;
598        case 'Z':
599            *ins++ = args->z;           /* 8 bits, zero or non-zero */
600            break;
601        default:
602            ALOGE("Invalid char %c in short signature of %s.%s",
603                *(desc-1), clazz->descriptor, method->name);
604            assert(false);
605            goto bail;
606        }
607
608        verifyCount++;
609        args++;
610    }
611
612#ifndef NDEBUG
613    if (verifyCount != method->insSize) {
614        ALOGE("Got vfycount=%d insSize=%d for %s.%s", verifyCount,
615            method->insSize, clazz->descriptor, method->name);
616        assert(false);
617        goto bail;
618    }
619#endif
620
621    if (dvmIsNativeMethod(method)) {
622        TRACE_METHOD_ENTER(self, method);
623        /*
624         * Because we leave no space for local variables, "curFrame" points
625         * directly at the method arguments.
626         */
627        (*method->nativeFunc)((u4*)self->interpSave.curFrame, pResult,
628                              method, self);
629        TRACE_METHOD_EXIT(self, method);
630    } else {
631        dvmInterpret(self, method, pResult);
632    }
633
634bail:
635    dvmPopFrame(self);
636}
637
638static void throwArgumentTypeMismatch(int argIndex, ClassObject* expected, DataObject* arg) {
639    std::string expectedClassName(dvmHumanReadableDescriptor(expected->descriptor));
640    std::string actualClassName = dvmHumanReadableType(arg);
641    dvmThrowExceptionFmt(gDvm.exIllegalArgumentException, "argument %d should have type %s, got %s",
642            argIndex + 1, expectedClassName.c_str(), actualClassName.c_str());
643}
644
645/*
646 * Invoke a method, using the specified arguments and return type, through
647 * one of the reflection interfaces.  Could be a virtual or direct method
648 * (including constructors).  Used for reflection.
649 *
650 * Deals with boxing/unboxing primitives and performs widening conversions.
651 *
652 * "invokeObj" will be null for a static method.
653 *
654 * If the invocation returns with an exception raised, we have to wrap it.
655 */
656Object* dvmInvokeMethod(Object* obj, const Method* method,
657    ArrayObject* argList, ArrayObject* params, ClassObject* returnType,
658    bool noAccessCheck)
659{
660    ClassObject* clazz;
661    Object* retObj = NULL;
662    Thread* self = dvmThreadSelf();
663    s4* ins;
664    int verifyCount, argListLength;
665    JValue retval;
666    bool needPop = false;
667
668    /* verify arg count */
669    if (argList != NULL)
670        argListLength = argList->length;
671    else
672        argListLength = 0;
673    if (argListLength != (int) params->length) {
674        dvmThrowExceptionFmt(gDvm.exIllegalArgumentException,
675            "wrong number of arguments; expected %d, got %d",
676            params->length, argListLength);
677        return NULL;
678    }
679
680    clazz = callPrep(self, method, obj, !noAccessCheck);
681    if (clazz == NULL)
682        return NULL;
683    needPop = true;
684
685    /* "ins" for new frame start at frame pointer plus locals */
686    ins = ((s4*)self->interpSave.curFrame) +
687        (method->registersSize - method->insSize);
688    verifyCount = 0;
689
690    //ALOGD("  FP is %p, INs live at >= %p", self->interpSave.curFrame, ins);
691
692    /* put "this" pointer into in0 if appropriate */
693    if (!dvmIsStaticMethod(method)) {
694        assert(obj != NULL);
695        *ins++ = (s4) obj;
696        verifyCount++;
697    }
698
699    /*
700     * Copy the args onto the stack.  Primitive types are converted when
701     * necessary, and object types are verified.
702     */
703    DataObject** args = (DataObject**)(void*)argList->contents;
704    ClassObject** types = (ClassObject**)(void*)params->contents;
705    for (int i = 0; i < argListLength; i++) {
706        int width = dvmConvertArgument(*args++, *types++, ins);
707        if (width < 0) {
708            dvmPopFrame(self);      // throw wants to pull PC out of stack
709            needPop = false;
710            throwArgumentTypeMismatch(i, *(types-1), *(args-1));
711            goto bail;
712        }
713
714        ins += width;
715        verifyCount += width;
716    }
717
718#ifndef NDEBUG
719    if (verifyCount != method->insSize) {
720        ALOGE("Got vfycount=%d insSize=%d for %s.%s", verifyCount,
721            method->insSize, clazz->descriptor, method->name);
722        assert(false);
723        goto bail;
724    }
725#endif
726
727    if (dvmIsNativeMethod(method)) {
728        TRACE_METHOD_ENTER(self, method);
729        /*
730         * Because we leave no space for local variables, "curFrame" points
731         * directly at the method arguments.
732         */
733        (*method->nativeFunc)((u4*)self->interpSave.curFrame, &retval,
734                              method, self);
735        TRACE_METHOD_EXIT(self, method);
736    } else {
737        dvmInterpret(self, method, &retval);
738    }
739
740    /*
741     * Pop the frame immediately.  The "wrap" calls below can cause
742     * allocations, and we don't want the GC to walk the now-dead frame.
743     */
744    dvmPopFrame(self);
745    needPop = false;
746
747    /*
748     * If an exception is raised, wrap and replace.  This is necessary
749     * because the invoked method could have thrown a checked exception
750     * that the caller wasn't prepared for.
751     *
752     * We might be able to do this up in the interpreted code, but that will
753     * leave us with a shortened stack trace in the top-level exception.
754     */
755    if (dvmCheckException(self)) {
756        dvmWrapException("Ljava/lang/reflect/InvocationTargetException;");
757    } else {
758        /*
759         * If this isn't a void method or constructor, convert the return type
760         * to an appropriate object.
761         *
762         * We don't do this when an exception is raised because the value
763         * in "retval" is undefined.
764         */
765        if (returnType != NULL) {
766            retObj = (Object*)dvmBoxPrimitive(retval, returnType);
767            dvmReleaseTrackedAlloc(retObj, NULL);
768        }
769    }
770
771bail:
772    if (needPop) {
773        dvmPopFrame(self);
774    }
775    return retObj;
776}
777
778struct LineNumFromPcContext {
779    u4 address;
780    u4 lineNum;
781};
782
783static int lineNumForPcCb(void *cnxt, u4 address, u4 lineNum)
784{
785    LineNumFromPcContext *pContext = (LineNumFromPcContext *)cnxt;
786
787    // We know that this callback will be called in
788    // ascending address order, so keep going until we find
789    // a match or we've just gone past it.
790
791    if (address > pContext->address) {
792        // The line number from the previous positions callback
793        // wil be the final result.
794        return 1;
795    }
796
797    pContext->lineNum = lineNum;
798
799    return (address == pContext->address) ? 1 : 0;
800}
801
802/*
803 * Determine the source file line number based on the program counter.
804 * "pc" is an offset, in 16-bit units, from the start of the method's code.
805 *
806 * Returns -1 if no match was found (possibly because the source files were
807 * compiled without "-g", so no line number information is present).
808 * Returns -2 for native methods (as expected in exception traces).
809 */
810int dvmLineNumFromPC(const Method* method, u4 relPc)
811{
812    const DexCode* pDexCode = dvmGetMethodCode(method);
813
814    if (pDexCode == NULL) {
815        if (dvmIsNativeMethod(method) && !dvmIsAbstractMethod(method))
816            return -2;
817        return -1;      /* can happen for abstract method stub */
818    }
819
820    LineNumFromPcContext context;
821    memset(&context, 0, sizeof(context));
822    context.address = relPc;
823    // A method with no line number info should return -1
824    context.lineNum = -1;
825
826    dexDecodeDebugInfo(method->clazz->pDvmDex->pDexFile, pDexCode,
827            method->clazz->descriptor,
828            method->prototype.protoIdx,
829            method->accessFlags,
830            lineNumForPcCb, NULL, &context);
831
832    return context.lineNum;
833}
834
835/*
836 * Compute the frame depth.
837 *
838 * Excludes "break" frames.
839 */
840int dvmComputeExactFrameDepth(const void* fp)
841{
842    int count = 0;
843
844    for ( ; fp != NULL; fp = SAVEAREA_FROM_FP(fp)->prevFrame) {
845        if (!dvmIsBreakFrame((u4*)fp))
846            count++;
847    }
848
849    return count;
850}
851
852/*
853 * Compute the "vague" frame depth, which is just a pointer subtraction.
854 * The result is NOT an overly generous assessment of the number of
855 * frames; the only meaningful use is to compare against the result of
856 * an earlier invocation.
857 *
858 * Useful for implementing single-step debugger modes, which may need to
859 * call this for every instruction.
860 */
861int dvmComputeVagueFrameDepth(Thread* thread, const void* fp)
862{
863    const u1* interpStackStart = thread->interpStackStart;
864
865    assert((u1*) fp >= interpStackStart - thread->interpStackSize);
866    assert((u1*) fp < interpStackStart);
867    return interpStackStart - (u1*) fp;
868}
869
870/*
871 * Get the calling frame.  Pass in the current fp.
872 *
873 * Skip "break" frames and reflection invoke frames.
874 */
875void* dvmGetCallerFP(const void* curFrame)
876{
877    void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame;
878    StackSaveArea* saveArea;
879
880retry:
881    if (dvmIsBreakFrame((u4*)caller)) {
882        /* pop up one more */
883        caller = SAVEAREA_FROM_FP(caller)->prevFrame;
884        if (caller == NULL)
885            return NULL;        /* hit the top */
886
887        /*
888         * If we got here by java.lang.reflect.Method.invoke(), we don't
889         * want to return Method's class loader.  Shift up one and try
890         * again.
891         */
892        saveArea = SAVEAREA_FROM_FP(caller);
893        if (dvmIsReflectionMethod(saveArea->method)) {
894            caller = saveArea->prevFrame;
895            assert(caller != NULL);
896            goto retry;
897        }
898    }
899
900    return caller;
901}
902
903/*
904 * Get the caller's class.  Pass in the current fp.
905 *
906 * This is used by e.g. java.lang.Class.
907 */
908ClassObject* dvmGetCallerClass(const void* curFrame)
909{
910    void* caller;
911
912    caller = dvmGetCallerFP(curFrame);
913    if (caller == NULL)
914        return NULL;
915
916    return SAVEAREA_FROM_FP(caller)->method->clazz;
917}
918
919/*
920 * Get the caller's caller's class.  Pass in the current fp.
921 *
922 * This is used by e.g. java.lang.Class, which wants to know about the
923 * class loader of the method that called it.
924 */
925ClassObject* dvmGetCaller2Class(const void* curFrame)
926{
927    void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame;
928    void* callerCaller;
929
930    /* at the top? */
931    if (dvmIsBreakFrame((u4*)caller) &&
932        SAVEAREA_FROM_FP(caller)->prevFrame == NULL)
933        return NULL;
934
935    /* go one more */
936    callerCaller = dvmGetCallerFP(caller);
937    if (callerCaller == NULL)
938        return NULL;
939
940    return SAVEAREA_FROM_FP(callerCaller)->method->clazz;
941}
942
943/*
944 * Get the caller's caller's caller's class.  Pass in the current fp.
945 *
946 * This is used by e.g. java.lang.Class, which wants to know about the
947 * class loader of the method that called it.
948 */
949ClassObject* dvmGetCaller3Class(const void* curFrame)
950{
951    void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame;
952    int i;
953
954    /* at the top? */
955    if (dvmIsBreakFrame((u4*)caller) &&
956        SAVEAREA_FROM_FP(caller)->prevFrame == NULL)
957        return NULL;
958
959    /* Walk up two frames if possible. */
960    for (i = 0; i < 2; i++) {
961        caller = dvmGetCallerFP(caller);
962        if (caller == NULL)
963            return NULL;
964    }
965
966    return SAVEAREA_FROM_FP(caller)->method->clazz;
967}
968
969/*
970 * Fill a flat array of methods that comprise the current interpreter
971 * stack trace.  Pass in the current frame ptr.  Break frames are
972 * skipped, but reflection invocations are not.
973 *
974 * The current frame will be in element 0.
975 */
976void dvmFillStackTraceArray(const void* fp, const Method** array, size_t length)
977{
978    assert(fp != NULL);
979    assert(array != NULL);
980    size_t i = 0;
981    while (fp != NULL) {
982        if (!dvmIsBreakFrame((u4*)fp)) {
983            assert(i < length);
984            array[i++] = SAVEAREA_FROM_FP(fp)->method;
985        }
986        fp = SAVEAREA_FROM_FP(fp)->prevFrame;
987    }
988}
989
990/*
991 * Open up the reserved area and throw an exception.  The reserved area
992 * should only be needed to create and initialize the exception itself.
993 *
994 * If we already opened it and we're continuing to overflow, abort the VM.
995 *
996 * We have to leave the "reserved" area open until the "catch" handler has
997 * finished doing its processing.  This is because the catch handler may
998 * need to resolve classes, which requires calling into the class loader if
999 * the classes aren't already in the "initiating loader" list.
1000 */
1001void dvmHandleStackOverflow(Thread* self, const Method* method)
1002{
1003    /*
1004     * Can we make the reserved area available?
1005     */
1006    if (self->stackOverflowed) {
1007        /*
1008         * Already did, nothing to do but bail.
1009         */
1010        ALOGE("DalvikVM: double-overflow of stack in threadid=%d; aborting",
1011            self->threadId);
1012        dvmDumpThread(self, false);
1013        dvmAbort();
1014    }
1015
1016    /* open it up to the full range */
1017    ALOGI("threadid=%d: stack overflow on call to %s.%s:%s",
1018        self->threadId,
1019        method->clazz->descriptor, method->name, method->shorty);
1020    StackSaveArea* saveArea = SAVEAREA_FROM_FP(self->interpSave.curFrame);
1021    ALOGI("  method requires %d+%d+%d=%d bytes, fp is %p (%d left)",
1022        method->registersSize * 4, sizeof(StackSaveArea), method->outsSize * 4,
1023        (method->registersSize + method->outsSize) * 4 + sizeof(StackSaveArea),
1024        saveArea, (u1*) saveArea - self->interpStackEnd);
1025    ALOGI("  expanding stack end (%p to %p)", self->interpStackEnd,
1026        self->interpStackStart - self->interpStackSize);
1027    //dvmDumpThread(self, false);
1028    self->interpStackEnd = self->interpStackStart - self->interpStackSize;
1029    self->stackOverflowed = true;
1030
1031    /*
1032     * If we were trying to throw an exception when the stack overflowed,
1033     * we will blow up when doing the class lookup on StackOverflowError
1034     * because of the pending exception.  So, we clear it and make it
1035     * the cause of the SOE.
1036     */
1037    Object* excep = dvmGetException(self);
1038    if (excep != NULL) {
1039        ALOGW("Stack overflow while throwing exception");
1040        dvmClearException(self);
1041    }
1042    dvmThrowChainedException(gDvm.exStackOverflowError, NULL, excep);
1043}
1044
1045/*
1046 * Reduce the available stack size.  By this point we should have finished
1047 * our overflow processing.
1048 */
1049void dvmCleanupStackOverflow(Thread* self, const Object* exception)
1050{
1051    const u1* newStackEnd;
1052
1053    assert(self->stackOverflowed);
1054
1055    if (exception->clazz != gDvm.exStackOverflowError) {
1056        /* exception caused during SOE, not the SOE itself */
1057        return;
1058    }
1059
1060    newStackEnd = (self->interpStackStart - self->interpStackSize)
1061        + STACK_OVERFLOW_RESERVE;
1062    if ((u1*)self->interpSave.curFrame <= newStackEnd) {
1063        ALOGE("Can't shrink stack: curFrame is in reserved area (%p %p)",
1064            self->interpStackEnd, self->interpSave.curFrame);
1065        dvmDumpThread(self, false);
1066        dvmAbort();
1067    }
1068
1069    self->interpStackEnd = newStackEnd;
1070    self->stackOverflowed = false;
1071
1072    ALOGI("Shrank stack (to %p, curFrame is %p)", self->interpStackEnd,
1073        self->interpSave.curFrame);
1074}
1075
1076
1077/*
1078 * Extract the object that is the target of a monitor-enter instruction
1079 * in the top stack frame of "thread".
1080 *
1081 * The other thread might be alive, so this has to work carefully.
1082 *
1083 * The thread list lock must be held.
1084 *
1085 * Returns "true" if we successfully recover the object.  "*pOwner" will
1086 * be NULL if we can't determine the owner for some reason (e.g. race
1087 * condition on ownership transfer).
1088 */
1089static bool extractMonitorEnterObject(Thread* thread, Object** pLockObj,
1090    Thread** pOwner)
1091{
1092    void* framePtr = thread->interpSave.curFrame;
1093
1094    if (framePtr == NULL || dvmIsBreakFrame((u4*)framePtr))
1095        return false;
1096
1097    const StackSaveArea* saveArea = SAVEAREA_FROM_FP(framePtr);
1098    const Method* method = saveArea->method;
1099    const u2* currentPc = saveArea->xtra.currentPc;
1100
1101    /* check Method* */
1102    if (!dvmLinearAllocContains(method, sizeof(Method))) {
1103        ALOGD("ExtrMon: method %p not valid", method);
1104        return false;
1105    }
1106
1107    /* check currentPc */
1108    u4 insnsSize = dvmGetMethodInsnsSize(method);
1109    if (currentPc < method->insns ||
1110        currentPc >= method->insns + insnsSize)
1111    {
1112        ALOGD("ExtrMon: insns %p not valid (%p - %p)",
1113            currentPc, method->insns, method->insns + insnsSize);
1114        return false;
1115    }
1116
1117    /* check the instruction */
1118    if ((*currentPc & 0xff) != OP_MONITOR_ENTER) {
1119        ALOGD("ExtrMon: insn at %p is not monitor-enter (0x%02x)",
1120            currentPc, *currentPc & 0xff);
1121        return false;
1122    }
1123
1124    /* get and check the register index */
1125    unsigned int reg = *currentPc >> 8;
1126    if (reg >= method->registersSize) {
1127        ALOGD("ExtrMon: invalid register %d (max %d)",
1128            reg, method->registersSize);
1129        return false;
1130    }
1131
1132    /* get and check the object in that register */
1133    u4* fp = (u4*) framePtr;
1134    Object* obj = (Object*) fp[reg];
1135    if (obj != NULL && !dvmIsHeapAddress(obj)) {
1136        ALOGD("ExtrMon: invalid object %p at %p[%d]", obj, fp, reg);
1137        return false;
1138    }
1139    *pLockObj = obj;
1140
1141    /*
1142     * Try to determine the object's lock holder; it's okay if this fails.
1143     *
1144     * We're assuming the thread list lock is already held by this thread.
1145     * If it's not, we may be living dangerously if we have to scan through
1146     * the thread list to find a match.  (The VM will generally be in a
1147     * suspended state when executing here, so this is a minor concern
1148     * unless we're dumping while threads are running, in which case there's
1149     * a good chance of stuff blowing up anyway.)
1150     */
1151    *pOwner = dvmGetObjectLockHolder(obj);
1152
1153    return true;
1154}
1155
1156static void printWaitMessage(const DebugOutputTarget* target, const char* detail, Object* obj,
1157        Thread* thread)
1158{
1159    std::string msg(StringPrintf("  - waiting %s <%p> ", detail, obj));
1160
1161    if (obj->clazz != gDvm.classJavaLangClass) {
1162        // I(16573)   - waiting on <0xf5feda38> (a java.util.LinkedList)
1163        // I(16573)   - waiting on <0xf5ed54f8> (a java.lang.Class<java.lang.ref.ReferenceQueue>)
1164        msg += "(a " + dvmHumanReadableType(obj) + ")";
1165    }
1166
1167    if (thread != NULL) {
1168        std::string threadName(dvmGetThreadName(thread));
1169        StringAppendF(&msg, " held by tid=%d (%s)", thread->threadId, threadName.c_str());
1170    }
1171
1172    dvmPrintDebugMessage(target, "%s\n", msg.c_str());
1173}
1174
1175/*
1176 * Dump stack frames, starting from the specified frame and moving down.
1177 *
1178 * Each frame holds a pointer to the currently executing method, and the
1179 * saved program counter from the caller ("previous" frame).  This means
1180 * we don't have the PC for the current method on the stack, which is
1181 * pretty reasonable since it's in the "PC register" for the VM.  Because
1182 * exceptions need to show the correct line number we actually *do* have
1183 * an updated version in the fame's "xtra.currentPc", but it's unreliable.
1184 *
1185 * Note "framePtr" could be NULL in rare circumstances.
1186 */
1187static void dumpFrames(const DebugOutputTarget* target, void* framePtr,
1188    Thread* thread)
1189{
1190    const StackSaveArea* saveArea;
1191    const Method* method;
1192    int checkCount = 0;
1193    const u2* currentPc = NULL;
1194    bool first = true;
1195
1196    /*
1197     * We call functions that require us to be holding the thread list lock.
1198     * It's probable that the caller has already done so, but it's not
1199     * guaranteed.  If it's not locked, lock it now.
1200     */
1201    bool needThreadUnlock = dvmTryLockThreadList();
1202
1203    /*
1204     * The "currentPc" is updated whenever we execute an instruction that
1205     * might throw an exception.  Show it here.
1206     */
1207    if (framePtr != NULL && !dvmIsBreakFrame((u4*)framePtr)) {
1208        saveArea = SAVEAREA_FROM_FP(framePtr);
1209
1210        if (saveArea->xtra.currentPc != NULL)
1211            currentPc = saveArea->xtra.currentPc;
1212    }
1213
1214    while (framePtr != NULL) {
1215        saveArea = SAVEAREA_FROM_FP(framePtr);
1216        method = saveArea->method;
1217
1218        if (dvmIsBreakFrame((u4*)framePtr)) {
1219            //dvmPrintDebugMessage(target, "  (break frame)\n");
1220        } else {
1221            int relPc;
1222
1223            if (currentPc != NULL)
1224                relPc = currentPc - saveArea->method->insns;
1225            else
1226                relPc = -1;
1227
1228            std::string methodName(dvmHumanReadableMethod(method, false));
1229            if (dvmIsNativeMethod(method)) {
1230                dvmPrintDebugMessage(target, "  at %s(Native Method)\n",
1231                        methodName.c_str());
1232            } else {
1233                dvmPrintDebugMessage(target, "  at %s(%s:%s%d)\n",
1234                        methodName.c_str(), dvmGetMethodSourceFile(method),
1235                        (relPc >= 0 && first) ? "~" : "",
1236                        relPc < 0 ? -1 : dvmLineNumFromPC(method, relPc));
1237            }
1238
1239            if (first) {
1240                /*
1241                 * Decorate WAIT and MONITOR threads with some detail on
1242                 * the first frame.
1243                 *
1244                 * warning: wait status not stable, even in suspend
1245                 */
1246                if (thread->status == THREAD_WAIT ||
1247                    thread->status == THREAD_TIMED_WAIT)
1248                {
1249                    Monitor* mon = thread->waitMonitor;
1250                    Object* obj = dvmGetMonitorObject(mon);
1251                    if (obj != NULL) {
1252                        Thread* joinThread = NULL;
1253                        if (obj->clazz == gDvm.classJavaLangVMThread) {
1254                            joinThread = dvmGetThreadFromThreadObject(obj);
1255                        }
1256                        printWaitMessage(target, "on", obj, joinThread);
1257                    }
1258                } else if (thread->status == THREAD_MONITOR) {
1259                    Object* obj;
1260                    Thread* owner;
1261                    if (extractMonitorEnterObject(thread, &obj, &owner)) {
1262                        printWaitMessage(target, "to lock", obj, owner);
1263                    }
1264                }
1265            }
1266        }
1267
1268        /*
1269         * Get saved PC for previous frame.  There's no savedPc in a "break"
1270         * frame, because that represents native or interpreted code
1271         * invoked by the VM.  The saved PC is sitting in the "PC register",
1272         * a local variable on the native stack.
1273         */
1274        currentPc = saveArea->savedPc;
1275
1276        first = false;
1277
1278        if (saveArea->prevFrame != NULL && saveArea->prevFrame <= framePtr) {
1279            ALOGW("Warning: loop in stack trace at frame %d (%p -> %p)",
1280                checkCount, framePtr, saveArea->prevFrame);
1281            break;
1282        }
1283        framePtr = saveArea->prevFrame;
1284
1285        checkCount++;
1286        if (checkCount > 300) {
1287            dvmPrintDebugMessage(target,
1288                "  ***** printed %d frames, not showing any more\n",
1289                checkCount);
1290            break;
1291        }
1292    }
1293
1294    if (needThreadUnlock) {
1295        dvmUnlockThreadList();
1296    }
1297}
1298
1299
1300/*
1301 * Dump the stack for the specified thread.
1302 */
1303void dvmDumpThreadStack(const DebugOutputTarget* target, Thread* thread)
1304{
1305    dumpFrames(target, thread->interpSave.curFrame, thread);
1306}
1307
1308/*
1309 * Dump the stack for the specified thread, which is still running.
1310 *
1311 * This is very dangerous, because stack frames are being pushed on and
1312 * popped off, and if the thread exits we'll be looking at freed memory.
1313 * The plan here is to take a snapshot of the stack and then dump that
1314 * to try to minimize the chances of catching it mid-update.  This should
1315 * work reasonably well on a single-CPU system.
1316 *
1317 * There is a small chance that calling here will crash the VM.
1318 */
1319void dvmDumpRunningThreadStack(const DebugOutputTarget* target, Thread* thread)
1320{
1321    StackSaveArea* saveArea;
1322    const u1* origStack;
1323    u1* stackCopy = NULL;
1324    int origSize, fpOffset;
1325    void* fp;
1326    int depthLimit = 200;
1327
1328    if (thread == NULL || thread->interpSave.curFrame == NULL) {
1329        dvmPrintDebugMessage(target,
1330            "DumpRunning: Thread at %p has no curFrame (threadid=%d)\n",
1331            thread, (thread != NULL) ? thread->threadId : 0);
1332        return;
1333    }
1334
1335    /* wait for a full quantum */
1336    sched_yield();
1337
1338    /* copy the info we need, then the stack itself */
1339    origSize = thread->interpStackSize;
1340    origStack = (const u1*) thread->interpStackStart - origSize;
1341    stackCopy = (u1*) malloc(origSize);
1342    fpOffset = (u1*) thread->interpSave.curFrame - origStack;
1343    memcpy(stackCopy, origStack, origSize);
1344
1345    /*
1346     * Run through the stack and rewrite the "prev" pointers.
1347     */
1348    //ALOGI("DR: fpOff=%d (from %p %p)",fpOffset, origStack,
1349    //     thread->interpSave.curFrame);
1350    fp = stackCopy + fpOffset;
1351    while (true) {
1352        int prevOffset;
1353
1354        if (depthLimit-- < 0) {
1355            /* we're probably screwed */
1356            dvmPrintDebugMessage(target, "DumpRunning: depth limit hit\n");
1357            dvmAbort();
1358        }
1359        saveArea = SAVEAREA_FROM_FP(fp);
1360        if (saveArea->prevFrame == NULL)
1361            break;
1362
1363        prevOffset = (u1*) saveArea->prevFrame - origStack;
1364        if (prevOffset < 0 || prevOffset > origSize) {
1365            dvmPrintDebugMessage(target,
1366                "DumpRunning: bad offset found: %d (from %p %p)\n",
1367                prevOffset, origStack, saveArea->prevFrame);
1368            saveArea->prevFrame = NULL;
1369            break;
1370        }
1371
1372        saveArea->prevFrame = (u4*)(stackCopy + prevOffset);
1373        fp = saveArea->prevFrame;
1374    }
1375
1376    /*
1377     * We still need to pass the Thread for some monitor wait stuff.
1378     */
1379    dumpFrames(target, stackCopy + fpOffset, thread);
1380    free(stackCopy);
1381}
1382
1383/*
1384 * Dump the native stack for the specified thread.
1385 */
1386void dvmDumpNativeStack(const DebugOutputTarget* target, pid_t tid)
1387{
1388#ifdef HAVE_ANDROID_OS
1389    const size_t MAX_DEPTH = 32;
1390    backtrace_frame_t backtrace[MAX_DEPTH];
1391    ssize_t frames = unwind_backtrace_thread(tid, backtrace, 0, MAX_DEPTH);
1392    if (frames > 0) {
1393        backtrace_symbol_t backtrace_symbols[MAX_DEPTH];
1394        get_backtrace_symbols(backtrace, frames, backtrace_symbols);
1395
1396        for (size_t i = 0; i < size_t(frames); i++) {
1397            char line[MAX_BACKTRACE_LINE_LENGTH];
1398            format_backtrace_line(i, &backtrace[i], &backtrace_symbols[i],
1399                    line, MAX_BACKTRACE_LINE_LENGTH);
1400            dvmPrintDebugMessage(target, "  %s\n", line);
1401        }
1402
1403        free_backtrace_symbols(backtrace_symbols, frames);
1404    } else {
1405        dvmPrintDebugMessage(target, "  (native backtrace unavailable)\n");
1406    }
1407#endif
1408}
1409