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