Stack.cpp revision b1212301d5cffc06907211d243a21d50c4419dc9
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        LOGW("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        LOGW("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        LOGW("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        LOGE("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        LOGW("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    //LOGD("  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    JNIEnv* env = self->jniEnv;
470    while (*desc != '\0') {
471        switch (*(desc++)) {
472            case 'D': case 'J': {
473                u8 val = va_arg(args, u8);
474                memcpy(ins, &val, 8);       // EABI prevents direct store
475                ins += 2;
476                verifyCount += 2;
477                break;
478            }
479            case 'F': {
480                /* floats were normalized to doubles; convert back */
481                float f = (float) va_arg(args, double);
482                *ins++ = dvmFloatToU4(f);
483                verifyCount++;
484                break;
485            }
486            case 'L': {     /* 'shorty' descr uses L for all refs, incl array */
487                void* arg = va_arg(args, void*);
488                assert(obj == NULL || dvmIsHeapAddress(obj));
489                jobject argObj = reinterpret_cast<jobject>(arg);
490                if (fromJni)
491                    *ins++ = (u4) dvmDecodeIndirectRef(env, argObj);
492                else
493                    *ins++ = (u4) argObj;
494                verifyCount++;
495                break;
496            }
497            default: {
498                /* Z B C S I -- all passed as 32-bit integers */
499                *ins++ = va_arg(args, u4);
500                verifyCount++;
501                break;
502            }
503        }
504    }
505
506#ifndef NDEBUG
507    if (verifyCount != method->insSize) {
508        LOGE("Got vfycount=%d insSize=%d for %s.%s", verifyCount,
509            method->insSize, clazz->descriptor, method->name);
510        assert(false);
511        goto bail;
512    }
513#endif
514
515    //dvmDumpThreadStack(dvmThreadSelf());
516
517    if (dvmIsNativeMethod(method)) {
518        TRACE_METHOD_ENTER(self, method);
519        /*
520         * Because we leave no space for local variables, "curFrame" points
521         * directly at the method arguments.
522         */
523        (*method->nativeFunc)((u4*)self->interpSave.curFrame, pResult,
524                              method, self);
525        TRACE_METHOD_EXIT(self, method);
526    } else {
527        dvmInterpret(self, method, pResult);
528    }
529
530#ifndef NDEBUG
531bail:
532#endif
533    dvmPopFrame(self);
534}
535
536/*
537 * Issue a method call with arguments provided in an array.  We process
538 * the contents of "args" by scanning the method signature.
539 *
540 * The values were likely placed into an uninitialized jvalue array using
541 * the field specifiers, which means that sub-32-bit fields (e.g. short,
542 * boolean) may not have 32 or 64 bits of valid data.  This is different
543 * from the varargs invocation where the C compiler does a widening
544 * conversion when calling a function.  As a result, we have to be a
545 * little more precise when pulling stuff out.
546 *
547 * "args" may be NULL if the method has no arguments.
548 */
549void dvmCallMethodA(Thread* self, const Method* method, Object* obj,
550    bool fromJni, JValue* pResult, const jvalue* args)
551{
552    const char* desc = &(method->shorty[1]); // [0] is the return type.
553    int verifyCount = 0;
554    ClassObject* clazz;
555    u4* ins;
556
557    clazz = callPrep(self, method, obj, false);
558    if (clazz == NULL)
559        return;
560
561    /* "ins" for new frame start at frame pointer plus locals */
562    ins = ((u4*)self->interpSave.curFrame) +
563        (method->registersSize - method->insSize);
564
565    /* put "this" pointer into in0 if appropriate */
566    if (!dvmIsStaticMethod(method)) {
567        assert(obj != NULL);
568        *ins++ = (u4) obj;              /* obj is a "real" ref */
569        verifyCount++;
570    }
571
572    JNIEnv* env = self->jniEnv;
573    while (*desc != '\0') {
574        switch (*desc++) {
575        case 'D':                       /* 64-bit quantity; have to use */
576        case 'J':                       /*  memcpy() in case of mis-alignment */
577            memcpy(ins, &args->j, 8);
578            ins += 2;
579            verifyCount++;              /* this needs an extra push */
580            break;
581        case 'L':                       /* includes array refs */
582            if (fromJni)
583                *ins++ = (u4) dvmDecodeIndirectRef(env, args->l);
584            else
585                *ins++ = (u4) args->l;
586            break;
587        case 'F':
588        case 'I':
589            *ins++ = args->i;           /* full 32 bits */
590            break;
591        case 'S':
592            *ins++ = args->s;           /* 16 bits, sign-extended */
593            break;
594        case 'C':
595            *ins++ = args->c;           /* 16 bits, unsigned */
596            break;
597        case 'B':
598            *ins++ = args->b;           /* 8 bits, sign-extended */
599            break;
600        case 'Z':
601            *ins++ = args->z;           /* 8 bits, zero or non-zero */
602            break;
603        default:
604            LOGE("Invalid char %c in short signature of %s.%s",
605                *(desc-1), clazz->descriptor, method->name);
606            assert(false);
607            goto bail;
608        }
609
610        verifyCount++;
611        args++;
612    }
613
614#ifndef NDEBUG
615    if (verifyCount != method->insSize) {
616        LOGE("Got vfycount=%d insSize=%d for %s.%s", verifyCount,
617            method->insSize, clazz->descriptor, method->name);
618        assert(false);
619        goto bail;
620    }
621#endif
622
623    if (dvmIsNativeMethod(method)) {
624        TRACE_METHOD_ENTER(self, method);
625        /*
626         * Because we leave no space for local variables, "curFrame" points
627         * directly at the method arguments.
628         */
629        (*method->nativeFunc)((u4*)self->interpSave.curFrame, pResult,
630                              method, self);
631        TRACE_METHOD_EXIT(self, method);
632    } else {
633        dvmInterpret(self, method, pResult);
634    }
635
636bail:
637    dvmPopFrame(self);
638}
639
640static void throwArgumentTypeMismatch(int argIndex, ClassObject* expected, DataObject* arg) {
641    std::string expectedClassName(dvmHumanReadableDescriptor(expected->descriptor));
642    std::string actualClassName = dvmHumanReadableType(arg);
643    dvmThrowExceptionFmt(gDvm.exIllegalArgumentException, "argument %d should have type %s, got %s",
644            argIndex + 1, expectedClassName.c_str(), actualClassName.c_str());
645}
646
647/*
648 * Invoke a method, using the specified arguments and return type, through
649 * one of the reflection interfaces.  Could be a virtual or direct method
650 * (including constructors).  Used for reflection.
651 *
652 * Deals with boxing/unboxing primitives and performs widening conversions.
653 *
654 * "invokeObj" will be null for a static method.
655 *
656 * If the invocation returns with an exception raised, we have to wrap it.
657 */
658Object* dvmInvokeMethod(Object* obj, const Method* method,
659    ArrayObject* argList, ArrayObject* params, ClassObject* returnType,
660    bool noAccessCheck)
661{
662    ClassObject* clazz;
663    Object* retObj = NULL;
664    Thread* self = dvmThreadSelf();
665    s4* ins;
666    int verifyCount, argListLength;
667    JValue retval;
668    bool needPop = false;
669
670    /* verify arg count */
671    if (argList != NULL)
672        argListLength = argList->length;
673    else
674        argListLength = 0;
675    if (argListLength != (int) params->length) {
676        dvmThrowExceptionFmt(gDvm.exIllegalArgumentException,
677            "wrong number of arguments; expected %d, got %d",
678            params->length, argListLength);
679        return NULL;
680    }
681
682    clazz = callPrep(self, method, obj, !noAccessCheck);
683    if (clazz == NULL)
684        return NULL;
685    needPop = true;
686
687    /* "ins" for new frame start at frame pointer plus locals */
688    ins = ((s4*)self->interpSave.curFrame) +
689        (method->registersSize - method->insSize);
690    verifyCount = 0;
691
692    //LOGD("  FP is %p, INs live at >= %p", self->interpSave.curFrame, ins);
693
694    /* put "this" pointer into in0 if appropriate */
695    if (!dvmIsStaticMethod(method)) {
696        assert(obj != NULL);
697        *ins++ = (s4) obj;
698        verifyCount++;
699    }
700
701    /*
702     * Copy the args onto the stack.  Primitive types are converted when
703     * necessary, and object types are verified.
704     */
705    DataObject** args = (DataObject**)(void*)argList->contents;
706    ClassObject** types = (ClassObject**)(void*)params->contents;
707    for (int i = 0; i < argListLength; i++) {
708        int width = dvmConvertArgument(*args++, *types++, ins);
709        if (width < 0) {
710            dvmPopFrame(self);      // throw wants to pull PC out of stack
711            needPop = false;
712            throwArgumentTypeMismatch(i, *(types-1), *(args-1));
713            goto bail;
714        }
715
716        ins += width;
717        verifyCount += width;
718    }
719
720#ifndef NDEBUG
721    if (verifyCount != method->insSize) {
722        LOGE("Got vfycount=%d insSize=%d for %s.%s", verifyCount,
723            method->insSize, clazz->descriptor, method->name);
724        assert(false);
725        goto bail;
726    }
727#endif
728
729    if (dvmIsNativeMethod(method)) {
730        TRACE_METHOD_ENTER(self, method);
731        /*
732         * Because we leave no space for local variables, "curFrame" points
733         * directly at the method arguments.
734         */
735        (*method->nativeFunc)((u4*)self->interpSave.curFrame, &retval,
736                              method, self);
737        TRACE_METHOD_EXIT(self, method);
738    } else {
739        dvmInterpret(self, method, &retval);
740    }
741
742    /*
743     * Pop the frame immediately.  The "wrap" calls below can cause
744     * allocations, and we don't want the GC to walk the now-dead frame.
745     */
746    dvmPopFrame(self);
747    needPop = false;
748
749    /*
750     * If an exception is raised, wrap and replace.  This is necessary
751     * because the invoked method could have thrown a checked exception
752     * that the caller wasn't prepared for.
753     *
754     * We might be able to do this up in the interpreted code, but that will
755     * leave us with a shortened stack trace in the top-level exception.
756     */
757    if (dvmCheckException(self)) {
758        dvmWrapException("Ljava/lang/reflect/InvocationTargetException;");
759    } else {
760        /*
761         * If this isn't a void method or constructor, convert the return type
762         * to an appropriate object.
763         *
764         * We don't do this when an exception is raised because the value
765         * in "retval" is undefined.
766         */
767        if (returnType != NULL) {
768            retObj = (Object*)dvmBoxPrimitive(retval, returnType);
769            dvmReleaseTrackedAlloc(retObj, NULL);
770        }
771    }
772
773bail:
774    if (needPop) {
775        dvmPopFrame(self);
776    }
777    return retObj;
778}
779
780struct LineNumFromPcContext {
781    u4 address;
782    u4 lineNum;
783};
784
785static int lineNumForPcCb(void *cnxt, u4 address, u4 lineNum)
786{
787    LineNumFromPcContext *pContext = (LineNumFromPcContext *)cnxt;
788
789    // We know that this callback will be called in
790    // ascending address order, so keep going until we find
791    // a match or we've just gone past it.
792
793    if (address > pContext->address) {
794        // The line number from the previous positions callback
795        // wil be the final result.
796        return 1;
797    }
798
799    pContext->lineNum = lineNum;
800
801    return (address == pContext->address) ? 1 : 0;
802}
803
804/*
805 * Determine the source file line number based on the program counter.
806 * "pc" is an offset, in 16-bit units, from the start of the method's code.
807 *
808 * Returns -1 if no match was found (possibly because the source files were
809 * compiled without "-g", so no line number information is present).
810 * Returns -2 for native methods (as expected in exception traces).
811 */
812int dvmLineNumFromPC(const Method* method, u4 relPc)
813{
814    const DexCode* pDexCode = dvmGetMethodCode(method);
815
816    if (pDexCode == NULL) {
817        if (dvmIsNativeMethod(method) && !dvmIsAbstractMethod(method))
818            return -2;
819        return -1;      /* can happen for abstract method stub */
820    }
821
822    LineNumFromPcContext context;
823    memset(&context, 0, sizeof(context));
824    context.address = relPc;
825    // A method with no line number info should return -1
826    context.lineNum = -1;
827
828    dexDecodeDebugInfo(method->clazz->pDvmDex->pDexFile, pDexCode,
829            method->clazz->descriptor,
830            method->prototype.protoIdx,
831            method->accessFlags,
832            lineNumForPcCb, NULL, &context);
833
834    return context.lineNum;
835}
836
837/*
838 * Compute the frame depth.
839 *
840 * Excludes "break" frames.
841 */
842int dvmComputeExactFrameDepth(const void* fp)
843{
844    int count = 0;
845
846    for ( ; fp != NULL; fp = SAVEAREA_FROM_FP(fp)->prevFrame) {
847        if (!dvmIsBreakFrame((u4*)fp))
848            count++;
849    }
850
851    return count;
852}
853
854/*
855 * Compute the "vague" frame depth, which is just a pointer subtraction.
856 * The result is NOT an overly generous assessment of the number of
857 * frames; the only meaningful use is to compare against the result of
858 * an earlier invocation.
859 *
860 * Useful for implementing single-step debugger modes, which may need to
861 * call this for every instruction.
862 */
863int dvmComputeVagueFrameDepth(Thread* thread, const void* fp)
864{
865    const u1* interpStackStart = thread->interpStackStart;
866
867    assert((u1*) fp >= interpStackStart - thread->interpStackSize);
868    assert((u1*) fp < interpStackStart);
869    return interpStackStart - (u1*) fp;
870}
871
872/*
873 * Get the calling frame.  Pass in the current fp.
874 *
875 * Skip "break" frames and reflection invoke frames.
876 */
877void* dvmGetCallerFP(const void* curFrame)
878{
879    void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame;
880    StackSaveArea* saveArea;
881
882retry:
883    if (dvmIsBreakFrame((u4*)caller)) {
884        /* pop up one more */
885        caller = SAVEAREA_FROM_FP(caller)->prevFrame;
886        if (caller == NULL)
887            return NULL;        /* hit the top */
888
889        /*
890         * If we got here by java.lang.reflect.Method.invoke(), we don't
891         * want to return Method's class loader.  Shift up one and try
892         * again.
893         */
894        saveArea = SAVEAREA_FROM_FP(caller);
895        if (dvmIsReflectionMethod(saveArea->method)) {
896            caller = saveArea->prevFrame;
897            assert(caller != NULL);
898            goto retry;
899        }
900    }
901
902    return caller;
903}
904
905/*
906 * Get the caller's class.  Pass in the current fp.
907 *
908 * This is used by e.g. java.lang.Class.
909 */
910ClassObject* dvmGetCallerClass(const void* curFrame)
911{
912    void* caller;
913
914    caller = dvmGetCallerFP(curFrame);
915    if (caller == NULL)
916        return NULL;
917
918    return SAVEAREA_FROM_FP(caller)->method->clazz;
919}
920
921/*
922 * Get the caller's caller's class.  Pass in the current fp.
923 *
924 * This is used by e.g. java.lang.Class, which wants to know about the
925 * class loader of the method that called it.
926 */
927ClassObject* dvmGetCaller2Class(const void* curFrame)
928{
929    void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame;
930    void* callerCaller;
931
932    /* at the top? */
933    if (dvmIsBreakFrame((u4*)caller) &&
934        SAVEAREA_FROM_FP(caller)->prevFrame == NULL)
935        return NULL;
936
937    /* go one more */
938    callerCaller = dvmGetCallerFP(caller);
939    if (callerCaller == NULL)
940        return NULL;
941
942    return SAVEAREA_FROM_FP(callerCaller)->method->clazz;
943}
944
945/*
946 * Get the caller's caller's caller's class.  Pass in the current fp.
947 *
948 * This is used by e.g. java.lang.Class, which wants to know about the
949 * class loader of the method that called it.
950 */
951ClassObject* dvmGetCaller3Class(const void* curFrame)
952{
953    void* caller = SAVEAREA_FROM_FP(curFrame)->prevFrame;
954    int i;
955
956    /* at the top? */
957    if (dvmIsBreakFrame((u4*)caller) &&
958        SAVEAREA_FROM_FP(caller)->prevFrame == NULL)
959        return NULL;
960
961    /* Walk up two frames if possible. */
962    for (i = 0; i < 2; i++) {
963        caller = dvmGetCallerFP(caller);
964        if (caller == NULL)
965            return NULL;
966    }
967
968    return SAVEAREA_FROM_FP(caller)->method->clazz;
969}
970
971/*
972 * Fill a flat array of methods that comprise the current interpreter
973 * stack trace.  Pass in the current frame ptr.  Break frames are
974 * skipped, but reflection invocations are not.
975 *
976 * The current frame will be in element 0.
977 */
978void dvmFillStackTraceArray(const void* fp, const Method** array, size_t length)
979{
980    assert(fp != NULL);
981    assert(array != NULL);
982    size_t i = 0;
983    while (fp != NULL) {
984        if (!dvmIsBreakFrame((u4*)fp)) {
985            assert(i < length);
986            array[i++] = SAVEAREA_FROM_FP(fp)->method;
987        }
988        fp = SAVEAREA_FROM_FP(fp)->prevFrame;
989    }
990}
991
992/*
993 * Open up the reserved area and throw an exception.  The reserved area
994 * should only be needed to create and initialize the exception itself.
995 *
996 * If we already opened it and we're continuing to overflow, abort the VM.
997 *
998 * We have to leave the "reserved" area open until the "catch" handler has
999 * finished doing its processing.  This is because the catch handler may
1000 * need to resolve classes, which requires calling into the class loader if
1001 * the classes aren't already in the "initiating loader" list.
1002 */
1003void dvmHandleStackOverflow(Thread* self, const Method* method)
1004{
1005    /*
1006     * Can we make the reserved area available?
1007     */
1008    if (self->stackOverflowed) {
1009        /*
1010         * Already did, nothing to do but bail.
1011         */
1012        LOGE("DalvikVM: double-overflow of stack in threadid=%d; aborting",
1013            self->threadId);
1014        dvmDumpThread(self, false);
1015        dvmAbort();
1016    }
1017
1018    /* open it up to the full range */
1019    LOGI("threadid=%d: stack overflow on call to %s.%s:%s",
1020        self->threadId,
1021        method->clazz->descriptor, method->name, method->shorty);
1022    StackSaveArea* saveArea = SAVEAREA_FROM_FP(self->interpSave.curFrame);
1023    LOGI("  method requires %d+%d+%d=%d bytes, fp is %p (%d left)",
1024        method->registersSize * 4, sizeof(StackSaveArea), method->outsSize * 4,
1025        (method->registersSize + method->outsSize) * 4 + sizeof(StackSaveArea),
1026        saveArea, (u1*) saveArea - self->interpStackEnd);
1027    LOGI("  expanding stack end (%p to %p)", self->interpStackEnd,
1028        self->interpStackStart - self->interpStackSize);
1029    //dvmDumpThread(self, false);
1030    self->interpStackEnd = self->interpStackStart - self->interpStackSize;
1031    self->stackOverflowed = true;
1032
1033    /*
1034     * If we were trying to throw an exception when the stack overflowed,
1035     * we will blow up when doing the class lookup on StackOverflowError
1036     * because of the pending exception.  So, we clear it and make it
1037     * the cause of the SOE.
1038     */
1039    Object* excep = dvmGetException(self);
1040    if (excep != NULL) {
1041        LOGW("Stack overflow while throwing exception");
1042        dvmClearException(self);
1043    }
1044    dvmThrowChainedException(gDvm.exStackOverflowError, NULL, excep);
1045}
1046
1047/*
1048 * Reduce the available stack size.  By this point we should have finished
1049 * our overflow processing.
1050 */
1051void dvmCleanupStackOverflow(Thread* self, const Object* exception)
1052{
1053    const u1* newStackEnd;
1054
1055    assert(self->stackOverflowed);
1056
1057    if (exception->clazz != gDvm.exStackOverflowError) {
1058        /* exception caused during SOE, not the SOE itself */
1059        return;
1060    }
1061
1062    newStackEnd = (self->interpStackStart - self->interpStackSize)
1063        + STACK_OVERFLOW_RESERVE;
1064    if ((u1*)self->interpSave.curFrame <= newStackEnd) {
1065        LOGE("Can't shrink stack: curFrame is in reserved area (%p %p)",
1066            self->interpStackEnd, self->interpSave.curFrame);
1067        dvmDumpThread(self, false);
1068        dvmAbort();
1069    }
1070
1071    self->interpStackEnd = newStackEnd;
1072    self->stackOverflowed = false;
1073
1074    LOGI("Shrank stack (to %p, curFrame is %p)", self->interpStackEnd,
1075        self->interpSave.curFrame);
1076}
1077
1078
1079/*
1080 * Extract the object that is the target of a monitor-enter instruction
1081 * in the top stack frame of "thread".
1082 *
1083 * The other thread might be alive, so this has to work carefully.
1084 *
1085 * The thread list lock must be held.
1086 *
1087 * Returns "true" if we successfully recover the object.  "*pOwner" will
1088 * be NULL if we can't determine the owner for some reason (e.g. race
1089 * condition on ownership transfer).
1090 */
1091static bool extractMonitorEnterObject(Thread* thread, Object** pLockObj,
1092    Thread** pOwner)
1093{
1094    void* framePtr = thread->interpSave.curFrame;
1095
1096    if (framePtr == NULL || dvmIsBreakFrame((u4*)framePtr))
1097        return false;
1098
1099    const StackSaveArea* saveArea = SAVEAREA_FROM_FP(framePtr);
1100    const Method* method = saveArea->method;
1101    const u2* currentPc = saveArea->xtra.currentPc;
1102
1103    /* check Method* */
1104    if (!dvmLinearAllocContains(method, sizeof(Method))) {
1105        LOGD("ExtrMon: method %p not valid", method);
1106        return false;
1107    }
1108
1109    /* check currentPc */
1110    u4 insnsSize = dvmGetMethodInsnsSize(method);
1111    if (currentPc < method->insns ||
1112        currentPc >= method->insns + insnsSize)
1113    {
1114        LOGD("ExtrMon: insns %p not valid (%p - %p)",
1115            currentPc, method->insns, method->insns + insnsSize);
1116        return false;
1117    }
1118
1119    /* check the instruction */
1120    if ((*currentPc & 0xff) != OP_MONITOR_ENTER) {
1121        LOGD("ExtrMon: insn at %p is not monitor-enter (0x%02x)",
1122            currentPc, *currentPc & 0xff);
1123        return false;
1124    }
1125
1126    /* get and check the register index */
1127    unsigned int reg = *currentPc >> 8;
1128    if (reg >= method->registersSize) {
1129        LOGD("ExtrMon: invalid register %d (max %d)",
1130            reg, method->registersSize);
1131        return false;
1132    }
1133
1134    /* get and check the object in that register */
1135    u4* fp = (u4*) framePtr;
1136    Object* obj = (Object*) fp[reg];
1137    if (obj != NULL && !dvmIsHeapAddress(obj)) {
1138        LOGD("ExtrMon: invalid object %p at %p[%d]", obj, fp, reg);
1139        return false;
1140    }
1141    *pLockObj = obj;
1142
1143    /*
1144     * Try to determine the object's lock holder; it's okay if this fails.
1145     *
1146     * We're assuming the thread list lock is already held by this thread.
1147     * If it's not, we may be living dangerously if we have to scan through
1148     * the thread list to find a match.  (The VM will generally be in a
1149     * suspended state when executing here, so this is a minor concern
1150     * unless we're dumping while threads are running, in which case there's
1151     * a good chance of stuff blowing up anyway.)
1152     */
1153    *pOwner = dvmGetObjectLockHolder(obj);
1154
1155    return true;
1156}
1157
1158static void printWaitMessage(const DebugOutputTarget* target, const char* detail, Object* obj,
1159        Thread* thread)
1160{
1161    std::string msg(StringPrintf("  - waiting %s <%p> ", detail, obj));
1162
1163    if (obj->clazz != gDvm.classJavaLangClass) {
1164        // I(16573)   - waiting on <0xf5feda38> (a java.util.LinkedList)
1165        // I(16573)   - waiting on <0xf5ed54f8> (a java.lang.Class<java.lang.ref.ReferenceQueue>)
1166        msg += "(a " + dvmHumanReadableType(obj) + ")";
1167    }
1168
1169    if (thread != NULL) {
1170        std::string threadName(dvmGetThreadName(thread));
1171        StringAppendF(&msg, " held by tid=%d (%s)", thread->threadId, threadName.c_str());
1172    }
1173
1174    dvmPrintDebugMessage(target, "%s\n", msg.c_str());
1175}
1176
1177/*
1178 * Dump stack frames, starting from the specified frame and moving down.
1179 *
1180 * Each frame holds a pointer to the currently executing method, and the
1181 * saved program counter from the caller ("previous" frame).  This means
1182 * we don't have the PC for the current method on the stack, which is
1183 * pretty reasonable since it's in the "PC register" for the VM.  Because
1184 * exceptions need to show the correct line number we actually *do* have
1185 * an updated version in the fame's "xtra.currentPc", but it's unreliable.
1186 *
1187 * Note "framePtr" could be NULL in rare circumstances.
1188 */
1189static void dumpFrames(const DebugOutputTarget* target, void* framePtr,
1190    Thread* thread)
1191{
1192    const StackSaveArea* saveArea;
1193    const Method* method;
1194    int checkCount = 0;
1195    const u2* currentPc = NULL;
1196    bool first = true;
1197
1198    /*
1199     * We call functions that require us to be holding the thread list lock.
1200     * It's probable that the caller has already done so, but it's not
1201     * guaranteed.  If it's not locked, lock it now.
1202     */
1203    bool needThreadUnlock = dvmTryLockThreadList();
1204
1205    /*
1206     * The "currentPc" is updated whenever we execute an instruction that
1207     * might throw an exception.  Show it here.
1208     */
1209    if (framePtr != NULL && !dvmIsBreakFrame((u4*)framePtr)) {
1210        saveArea = SAVEAREA_FROM_FP(framePtr);
1211
1212        if (saveArea->xtra.currentPc != NULL)
1213            currentPc = saveArea->xtra.currentPc;
1214    }
1215
1216    while (framePtr != NULL) {
1217        saveArea = SAVEAREA_FROM_FP(framePtr);
1218        method = saveArea->method;
1219
1220        if (dvmIsBreakFrame((u4*)framePtr)) {
1221            //dvmPrintDebugMessage(target, "  (break frame)\n");
1222        } else {
1223            int relPc;
1224
1225            if (currentPc != NULL)
1226                relPc = currentPc - saveArea->method->insns;
1227            else
1228                relPc = -1;
1229
1230            std::string methodName(dvmHumanReadableMethod(method, false));
1231            if (dvmIsNativeMethod(method)) {
1232                dvmPrintDebugMessage(target, "  at %s(Native Method)\n",
1233                        methodName.c_str());
1234            } else {
1235                dvmPrintDebugMessage(target, "  at %s(%s:%s%d)\n",
1236                        methodName.c_str(), dvmGetMethodSourceFile(method),
1237                        (relPc >= 0 && first) ? "~" : "",
1238                        relPc < 0 ? -1 : dvmLineNumFromPC(method, relPc));
1239            }
1240
1241            if (first) {
1242                /*
1243                 * Decorate WAIT and MONITOR threads with some detail on
1244                 * the first frame.
1245                 *
1246                 * warning: wait status not stable, even in suspend
1247                 */
1248                if (thread->status == THREAD_WAIT ||
1249                    thread->status == THREAD_TIMED_WAIT)
1250                {
1251                    Monitor* mon = thread->waitMonitor;
1252                    Object* obj = dvmGetMonitorObject(mon);
1253                    if (obj != NULL) {
1254                        Thread* joinThread = NULL;
1255                        if (obj->clazz == gDvm.classJavaLangVMThread) {
1256                            joinThread = dvmGetThreadFromThreadObject(obj);
1257                        }
1258                        printWaitMessage(target, "on", obj, joinThread);
1259                    }
1260                } else if (thread->status == THREAD_MONITOR) {
1261                    Object* obj;
1262                    Thread* owner;
1263                    if (extractMonitorEnterObject(thread, &obj, &owner)) {
1264                        printWaitMessage(target, "to lock", obj, owner);
1265                    }
1266                }
1267            }
1268        }
1269
1270        /*
1271         * Get saved PC for previous frame.  There's no savedPc in a "break"
1272         * frame, because that represents native or interpreted code
1273         * invoked by the VM.  The saved PC is sitting in the "PC register",
1274         * a local variable on the native stack.
1275         */
1276        currentPc = saveArea->savedPc;
1277
1278        first = false;
1279
1280        if (saveArea->prevFrame != NULL && saveArea->prevFrame <= framePtr) {
1281            LOGW("Warning: loop in stack trace at frame %d (%p -> %p)",
1282                checkCount, framePtr, saveArea->prevFrame);
1283            break;
1284        }
1285        framePtr = saveArea->prevFrame;
1286
1287        checkCount++;
1288        if (checkCount > 300) {
1289            dvmPrintDebugMessage(target,
1290                "  ***** printed %d frames, not showing any more\n",
1291                checkCount);
1292            break;
1293        }
1294    }
1295
1296    if (needThreadUnlock) {
1297        dvmUnlockThreadList();
1298    }
1299}
1300
1301
1302/*
1303 * Dump the stack for the specified thread.
1304 */
1305void dvmDumpThreadStack(const DebugOutputTarget* target, Thread* thread)
1306{
1307    dumpFrames(target, thread->interpSave.curFrame, thread);
1308}
1309
1310/*
1311 * Dump the stack for the specified thread, which is still running.
1312 *
1313 * This is very dangerous, because stack frames are being pushed on and
1314 * popped off, and if the thread exits we'll be looking at freed memory.
1315 * The plan here is to take a snapshot of the stack and then dump that
1316 * to try to minimize the chances of catching it mid-update.  This should
1317 * work reasonably well on a single-CPU system.
1318 *
1319 * There is a small chance that calling here will crash the VM.
1320 */
1321void dvmDumpRunningThreadStack(const DebugOutputTarget* target, Thread* thread)
1322{
1323    StackSaveArea* saveArea;
1324    const u1* origStack;
1325    u1* stackCopy = NULL;
1326    int origSize, fpOffset;
1327    void* fp;
1328    int depthLimit = 200;
1329
1330    if (thread == NULL || thread->interpSave.curFrame == NULL) {
1331        dvmPrintDebugMessage(target,
1332            "DumpRunning: Thread at %p has no curFrame (threadid=%d)\n",
1333            thread, (thread != NULL) ? thread->threadId : 0);
1334        return;
1335    }
1336
1337    /* wait for a full quantum */
1338    sched_yield();
1339
1340    /* copy the info we need, then the stack itself */
1341    origSize = thread->interpStackSize;
1342    origStack = (const u1*) thread->interpStackStart - origSize;
1343    stackCopy = (u1*) malloc(origSize);
1344    fpOffset = (u1*) thread->interpSave.curFrame - origStack;
1345    memcpy(stackCopy, origStack, origSize);
1346
1347    /*
1348     * Run through the stack and rewrite the "prev" pointers.
1349     */
1350    //LOGI("DR: fpOff=%d (from %p %p)",fpOffset, origStack,
1351    //     thread->interpSave.curFrame);
1352    fp = stackCopy + fpOffset;
1353    while (true) {
1354        int prevOffset;
1355
1356        if (depthLimit-- < 0) {
1357            /* we're probably screwed */
1358            dvmPrintDebugMessage(target, "DumpRunning: depth limit hit\n");
1359            dvmAbort();
1360        }
1361        saveArea = SAVEAREA_FROM_FP(fp);
1362        if (saveArea->prevFrame == NULL)
1363            break;
1364
1365        prevOffset = (u1*) saveArea->prevFrame - origStack;
1366        if (prevOffset < 0 || prevOffset > origSize) {
1367            dvmPrintDebugMessage(target,
1368                "DumpRunning: bad offset found: %d (from %p %p)\n",
1369                prevOffset, origStack, saveArea->prevFrame);
1370            saveArea->prevFrame = NULL;
1371            break;
1372        }
1373
1374        saveArea->prevFrame = (u4*)(stackCopy + prevOffset);
1375        fp = saveArea->prevFrame;
1376    }
1377
1378    /*
1379     * We still need to pass the Thread for some monitor wait stuff.
1380     */
1381    dumpFrames(target, stackCopy + fpOffset, thread);
1382    free(stackCopy);
1383}
1384
1385/*
1386 * Dump the native stack for the specified thread.
1387 */
1388void dvmDumpNativeStack(const DebugOutputTarget* target, pid_t tid)
1389{
1390#ifdef HAVE_ANDROID_OS
1391    const size_t MAX_DEPTH = 32;
1392    backtrace_frame_t backtrace[MAX_DEPTH];
1393    ssize_t frames = unwind_backtrace_thread(tid, backtrace, 0, MAX_DEPTH);
1394    if (frames > 0) {
1395        backtrace_symbol_t backtrace_symbols[MAX_DEPTH];
1396        get_backtrace_symbols(backtrace, frames, backtrace_symbols);
1397
1398        for (size_t i = 0; i < size_t(frames); i++) {
1399            const backtrace_symbol_t& symbol = backtrace_symbols[i];
1400            const char* mapName = symbol.map_info ? symbol.map_info->name : "<unknown>";
1401            const char* symbolName = symbol.demangled_name ? symbol.demangled_name : symbol.name;
1402            if (symbolName) {
1403                dvmPrintDebugMessage(target, "  #%02d  pc %08x  %s (%s)\n",
1404                        i, uint32_t(symbol.relative_pc), mapName, symbolName);
1405            } else {
1406                dvmPrintDebugMessage(target, "  #%02d  pc %08x  %s\n",
1407                        i, uint32_t(symbol.relative_pc), mapName);
1408            }
1409        }
1410
1411        free_backtrace_symbols(backtrace_symbols, frames);
1412    }
1413#endif
1414}
1415