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