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